【发布时间】:2010-11-25 12:12:24
【问题描述】:
假设我有三个值构造函数:
A { a :: Int }
B { b :: Char }
C { c :: Bool }
我想创建X 和Y 两种类型,这样X 类型的值可以是A、B 或C,如下所示:
data X = A {...} | B {...} | C {...}
而Y 类型的值只能是A 或B,如下所示:
data Y = A {...} | B {...}
这样我就可以编写如下代码:
foo :: X -> Int -- can pattern match
foo (A _) = 1
foo (B _) = 2
foo (C _) = 3
bar :: Y -> Bool -- also can pattern match with the same constructors
bar (A _) = true
bar (B _) = false
baz = A 1 -- baz is inferred to be a type that can fit in both X and Y
我知道我可以将构造函数包装在 X 和 Y 的定义中,如下所示:
data X = XA A | XB B | XC C
data Y = YA A | YB B
但这似乎不整洁(必须一直输入XA A 等)。我可以将A、B和C的内容扩展为X和Y的定义,但是A等非常复杂,我不想重复定义。
这对 Haskell 是否可行,包括任何 GHC 扩展?
编辑
GADT 似乎可以按要求回答我的问题(因此我将散热器的回答标记为正确),但仍然不够灵活,无法满足我的需要。例如,据我所知,您不能执行以下操作:
func1 :: [XY Y_] -- returns a list of items that can only be A or B
func1 = ...
func2 = func1 ++ [C True] -- adding a C item to the list
func2 应该输入为[XY X_],但这在 Haskell 中是不可能的(除非我的实验是错误的)。
经过更多的网络搜索,我真正想要的是 OCaml 的多态变体(据我所知)仅存在于 OCaml 中(着眼于更“实用”而不是“学术”语言)。
编辑 2
查看comonad的回答。看来真的可以,不过我觉得这个问题最好不要重写太多次。 :-)
【问题讨论】:
-
您对
foo和bar的定义不会进行类型检查,因为根据定义A _是A类型的值,而不是X或Y。不能有其他类型 (X) 具有相同的构造函数。 -
另一种看待它的方式:
A有什么类型?只能有一个,所以不能同时是Int -> X和Int -> Y。 -
jetxee 和 Antal S-Z:我知道我对
foo和bar的定义不会进行类型检查,但我希望类似的东西是有效的 Haskell。例如,对于类型类,read x(其中x是String)可以(在某种意义上)具有多个类型。