您可以使用数据类型来封装所有形状,也可以使用存在量化。这两种选择都有优点和缺点。你正面临“表达问题”。选择正确的选项取决于您的架构,因此我将详细说明两者。
我们假设您对形状有类似的定义:
data Circle = Circle { circleCenter :: Point, circleRadius :: Float }
data Rectangle = Rectangle { rectTopLeft :: Point, rectSize :: Size }
data Square = Square { squareTopLeft :: Point, squareSize :: Float }
...以及一些功能drawCircle
,drawRectangle
和drawSquare
。
使用数据类型
data Shape
= Circle Cirle
| Rectangle Rectangle
| Square Square
draw :: Shape -> IO ()
draw (Circle c) = drawCircle c
draw (Rectangle r) = drawRectangle r
draw (Square s) = drawSquare s
这种模式允许您轻松添加新功能(如shapeArea
、shiftShape
等...),但很难添加新形状,尤其是对于您库的用户而言。
使用存在量化
{-# LANGUAGE ExistentialQuantification #-}
-- Instead of using a datatype, we use a typeclass
class Shape s where
draw :: s -> IO ()
instance Shape Circle where
draw = drawCircle
instance Shape Rectangle where
draw = drawRectangle
instance Shape Square where
draw = drawSquare
-- Can't use newtype with ExistentialQuantification
data Sh = forall s. Shape s => Sh s
instance Shape Sh where
draw (Sh s) = draw s
使用此解决方案,您或用户将能够轻松添加新形状,但添加新功能可能会稍微复杂一些。
您还可以将类型类“降级”为数据类型,并将类型类成员“降级”为记录字段,如本文所述,正如 leftaroundabout 的答案中提到的那样。
我无法进一步帮助您,因为我不详细了解您的代码。如果您仍然需要帮助选择,请在评论中告诉我:)