To grasp the best styles (starting almost from scratch), I went on to model two-dimensional figures with area calculations, for example:
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 shapes.
This is great, but it occurred to me to try the following:
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 great. In order to hide the information, I modify the module declaration to look like this:
module TwoDShapes (TwoDShape, area, aCircle, anEllipse, aRectangle, aTriangle)
and, to my surprise, this 1) works and 2) in ghci aCircle is rated as TwoDShapeParams 1.0 1.0 3.1415927 , which is true, but I do not understand how the view of TwoDShapeParams is visible outside the module. I'm not sure what I expected, but not that.
I would really like the typeclass class, its method and smart constructors to be visible outside the module and nothing more. It can be done?