假设我有三个值构造函数:
A { a :: Int }
B { b :: Char }
C { c :: Bool }
我想创建两种类型X
and Y
这样类型的值X
可以是一个A
, B
or C
,像这样:
data X = A {...} | B {...} | C {...}
和类型的值Y
只能是一个A
or 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
and Y
像这样:
data X = XA A | XB B | XC C
data Y = YA A | YB B
但这似乎不整洁(必须输入XA A
等等)。我可以扩展内容A
, B
, and C
的定义X
and Y
, but A
等等非常复杂,我不想重复定义。
这对于 Haskell(包括任何 GHC 扩展)来说可能吗?
Edit
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 中(着眼于更“实用”而不是“学术”语言)。
Edit 2
请参阅 comonad 的回答。看起来确实可以做到,但是我觉得这个问题最好不要重写太多次。 :-)