扩展@carsten-könig 的答案,使用 GADT 可以静态地确保仅当静态已知颜色存在时才会使用某些功能,而其他功能可以在所有形状上通用定义。
{-# LANGUAGE GADTs #-}
module Shapes where
data Colour = Red | Green | Blue deriving (Show, Eq, Enum)
data Geometry = Star | Square deriving (Show, Eq, Enum)
我们引入了两种类型,它们的构造函数我们不关心,但 Haskell 可以区分它们。
data Filled
data Blank
我们现在添加一个类型参数到Shape
. 根据是否将 aColour
分配给形状,我们的Shape
构造函数的返回类型会有所不同。
data Shape a where
Coloured :: Colour -> Geometry -> Shape Filled
UnColoured :: Geometry -> Shape Blank
我们现在可以编写保色函数,例如将 aShape
转换为正方形:
toSquare :: Shape a -> Shape a
toSquare (Coloured col _) = Coloured col Square
toSquare (UnColoured _) = UnColoured Square
或者我们可以仅在对其进行此操作有意义的子集上定义一个函数:safeSetColour
该函数是否拒绝覆盖先前分配的颜色,而getColour
该函数是否仅在具有颜色Shape
的 s 上工作并提取它。
safeSetColour :: Shape Blank -> Colour -> Shape Filled
safeSetColour (UnColoured g) col = Coloured col g
getColour :: Shape Filled -> Colour
getColour (Coloured col _) = col
现在,只有当您需要静态确保 Shape 是or时, Either
monad 才会出现:Filled
Blank
decide :: Shape a -> Either (Shape Filled) (Shape Blank)
decide s@(Coloured _ _) = Left s
decide s@(UnColoured _) = Right s