如何为任何数据构造函数编写泛型函数?

时间:2017-02-04 08:07:29

标签: haskell

假设我在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) = ...

这就是我真正想要的。

1 个答案:

答案 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。