2017-02-04 64 views
1

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

这样,我的作品实际上有两个属性的“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

你的意图是让它像'place(One x)= x;地方(两个x)= x'? –

+0

是的,我不想为每个构造函数都有一个函数,而只想为它们提供一个函数。 –

+0

通过定义'Point'来让你的问题自成一体。 – Jubobs

回答

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你必须使用一个自定义和类型来表达休息的分解。例如。

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 

模板哈斯克尔也可以解决这个问题,但它是矫枉过正,IMO。

+0

仍然不完全是我所期待的,如果你有几个构造函数,但是如果你有10个构造函数,并且它们都有共享函数,那么你的建议就可以,那么对于你的解决方案,我将不得不重复' place :: a}'10次。一定会有更好的办法。 –

+0

@DovydasRupšys如果您正确地使用数据,请按照下面的建议操作。 – ThreeFx

+0

@DovydasRupšys我不认为有一个更简单的方法。你可以使用Template Haskell自动生成你想要的函数,它可以像在宏系统中那样为你生成代码,但是为此设置它需要小心。如果你有大量的类型/构造函数,这可能是值得的,但否则它需要太多的努力。 – chi