Hi, In order to grasp better typeclasses (starting pretty much form scratch) I had a go at modelling 2-D shapes with area calculations, like this:
module TwoDShapes where
class TwoDShape s where
area :: s -> Float
data Circle = Circle Float deriving Show
aCircle radius | radius < 0 = error "circle radius must be non-negative"
| otherwise = Circle radius
instance TwoDShape Circle where
area (Circle radius) = pi * radius * radius
data Ellipse = Ellipse Float Float deriving Show
anEllipse axis_a axis_b | axis_a < 0 || axis_b < 0 = error "ellipse axis length must be non-negative"
| otherwise = Ellipse axis_a axis_b
instance TwoDShape Ellipse where
area (Ellipse axis_a axis_b) = pi * axis_a * axis_b
And so on for other kinds of shape.
This is fine but it occurred to me to try this:
module TwoDShapes where
class TwoDShape s where
area :: s -> Float
data TwoDShapeParams = TwoDShapeParams Float Float Float deriving Show
instance TwoDShape TwoDShapeParams where
area (TwoDShapeParams length_a length_b constant) = foldl (*) 1 [length_a, length_b, constant]
aCircle radius | radius < 0 = error "circle radius must be non-negative"
| otherwise = TwoDShapeParams radius radius pi
anEllipse axis_a axis_b | axis_a < 0 || axis_b < 0 = error "ellipse axis length must be non-negative"
| otherwise = TwoDShapeParams axis_a axis_b pi
etc. which is also fine. With the goal of information hiding I change the module declaration to look like this:
module TwoDShapes (TwoDShape, area, aCircle, anEllipse, aRectangle, aTriangle)
and slightly to my surprise this 1) works and 2) in ghci aCircle
evaluates to TwoDShapeParams 1.0 1.0 3.1415927
which is true but I don't understand how the type TwoDShapeParams
is visible outside the module. I'm not sure what I was expecting, but not this.
What I'd really like is for the typeclass, it's method and the “smart constructors” to be visible outside the module and nothing else. Can that be done?