Чтобы лучше понять классы типов (начиная практически с нуля), я попытался смоделировать 2-D фигуры с вычислением площади, например:
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
И так далее для других видов фигуры.
Это нормально, но мне пришло в голову попробовать это:
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
и т.д.. что тоже хорошо. С целью сокрытия информации я изменяю объявление модуля, чтобы оно выглядело так:
module TwoDShapes (TwoDShape, area, aCircle, anEllipse, aRectangle, aTriangle)
и, к моему удивлению, это 1) работает и 2) в ghci aCircle
оценивается как TwoDShapeParams 1.0 1.0 3.1415927
, что верно, но я не понимаю, как тип TwoDShapeParams
виден за пределами модуля. Я не уверен, что я ожидал, но не это.
Что мне действительно нравится, так это чтобы класс типов, его метод и «умные конструкторы» были видны за пределами модуля и ничего больше. Можно ли это сделать?