2011-12-27 20 views
1

比方说,我想创建一个复杂的数据结构由多个相互递归的数据类型,多类型的变量,以及一些功能对这些类型的操作:复合型与抽取式功能

data Foo x y z = FooA x | FooB (Bar x y z) | FooC (Foo x y z) | FooD (Baz x y z) 
data Bar x y z = BarA y | BarB (Baz x y z) | BarC (Bar x y z) | BarD (Foo x y z) 
data Baz x y z = BazA z | BazB (Foo x y z) | BazC (Baz x y z) | BazD (Bar x y z) 

f :: Foo x y z -> Bar x y z -> Baz x y z 
g :: Bar x y z -> Baz x y z -> Foo x y z 

有我可以捆绑x y z类型的方式,给他们一个名称t,并在我真正需要时抽出xyz类型?我不想在我的数据和函数类型声明中扩散x y z,因为添加额外的参数可能会影响很多代码。

data Foo t = FooA (GetX t) | FooB (Bar t) | FooC (Foo t) | FooD (Baz t) 
data Bar t = BarA (GetY t) | BarB (Baz t) | BarC (Bar t) | BarD (Foo t) 
data Baz t = BazA (GetZ t) | BazB (Foo t) | BazC (Baz t) | BazD (Bar t) 

f :: Foo t -> Bar t -> Baz t 
g :: Bar t -> Baz t -> Foo t 

不知如何定义GetXGetY,和GetZ型“功能”从束提取组件类型。

回答

1

你可以用type families来做到这一点,但它几乎肯定是矫枉过正;通常最好设计您的数据类型,以便将来不需要任何其他参数。当然,这与预测未来非常接近,但如果有疑问,您应该添加一个参数而不是使用具体的类型:)

如果您有一个具体示例,我可以给出更具体的建议,但通常这里要做的最好的事情就是继续使用这些参数,或者找出一种方法来抽象出三种类型之间的关系,以便只需要一个完全指定其他参数的参数(而不仅仅是一个列表类型)。

不过,这里有一个如何与类型家庭实现它的一个例子:

type family GetX t 
type instance GetX (a,b,c) = a 

type family GetY t 
type instance GetY (a,b,c) = b 

type family GetZ t 
type instance GetZ (a,b,c) = c 
+0

整洁!有没有办法使用记录语法,而不是简单的元组,以便每个类型的家庭只能处理它感兴趣的领域,使它独立于元组的元组? – pat 2011-12-27 19:12:09

+0

这些不是元组值,它们是元组* *类型* - 在'(1,2,3)::(Int,Int,Int)'中,这些类型函数在模式匹配上的是'( Int,Int,Int)'部分。所以,不,没有记录,对不起:) – ehird 2011-12-27 19:21:10

+0

另一个答案可能是“如果Haskell有可能的记录类型,但它不会”。另请参阅关于如何改进Has​​kell记录系统的永无休止的讨论。 – glaebhoerl 2011-12-27 19:54:06

0

这将是一个基本类型级拉姆达的等价物。

type t = (\f -> f x y z) 

t Foo --> (\f -> f x y z) Foo --> Foo x y z 

除,当然,tFoo被翻转。

无论如何,Haskell没有真正的类型级lambda表达式。但你可能想看看这个相关问题的答案:Lambda for type expressions in Haskell?