如何为任何数据构造函数编写通用函数?

大卫·鲁普西斯(DavidRupšys)

假设我在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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章