假设我在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数据有效地是2个不同的东西,一块和一块,我试图通过继承来实现这一点,但这只是一个不好的方法。通过以下方式分离数据解决了该问题。
data PieceKind = One | Two | ... | n
data Piece a b = Piece a PieceKind
这样,我的Piece便有效地具有两个属性“ a”(在我的情况下,这是一个片断的位置)以及PieceKind,这样我就可以编写place函数,而不必在下面的每种片断中都重复它办法:
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) = ...
这就是我真正想要的。
将记录用于公共字段
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
使用自定义总和类型来表达其余的因式分解。例如
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,这太过分了。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句