假设我在Haskell中有这些数据定义。
data Point a = Point a a
data Piece a = One a | Two a
我希望有一个像
这样的功能place :: Num a => Piece (Point a) -> Point a
place (Piece x) = x
我怎么做,因为haskell不允许该特定形式的功能。
解决方案
问题在于我的数据定义(多年的经验编程在这里干扰......)。我希望我的Piece数据有效地成为两件不同的东西,一件作品,也是一件作品,我试图通过继承实现这一点,这只是一种糟糕的方法。以下列方式分离数据解决了这个问题。
data PieceKind = One | Two | ... | n
data Piece a b = Piece a PieceKind
这样我的作品有效地具有两个属性" a" (在我的情况下,这是一个片段的位置)和PieceKind,这样我就能够编写场所功能,而不必以下列方式为每种片段重复它:
place :: Num a => Piece (Point a) PieceKind -> Point a
place (Piece x _) = x
此外,我还能够为特定类型的作品编写函数:
place :: Num a => Piece (Point a) PieceKind -> Point a
place (Piece _ One) = ...
这就是我真正想要的。
答案 0 :(得分:2)
使用公共字段的记录
data Piece a = One { place :: a } | Two { place :: a }
-- place automatically defined
或分解公共数据
data Piece a = Piece Bool a
place :: Piece a -> a
place (Piece _ x) = x
-- optionally:
pattern One x = Piece False x
pattern Two x = Piece True x
在一般情况下,您必须使用自定义和类型来表示其余的分解,而不是Bool
。 E.g。
data T a = A Int a | B Bool a
变为
data T a = T (Either Int Bool) a
-- optionally:
pattern A n x = T (Left n) x
pattern B b x = T (Right b) x
模板Haskell也可以解决这个问题,但它有点矫枉过正,IMO。