基本用法
启用 GADTs
扩展后,除常规数据声明外,还可以声明广义代数数据类型,如下所示:
data DataType a where
Constr1 :: Int -> a -> Foo a -> DataType a
Constr2 :: Show a => a -> DataType a
Constr3 :: DataType Int
GADT 声明明确列出了数据类型具有的所有构造函数的类型。与常规数据类型声明不同,构造函数的类型可以是任何 N-ary(包括 nullary)函数,最终会导致应用于某些参数的数据类型。
在这种情况下,我们宣称 DataType
类型有三个构造函数:Constr1
,Constr2
和 Constr3
。
Constr1
构造函数与使用常规数据声明声明的构造函数没有什么不同:data DataType a = Constr1 Int a (Foo a) | ...
但是 Constr2
要求 a
有一个 Show
的实例,因此在使用构造函数时,实例需要存在。另一方面,当模式匹配时,a
是 Show
的一个实例的事实进入范围,所以你可以写:
foo::DataType a -> String
foo val = case val of
Constr2 x -> show x
...
请注意,Show a
约束不会出现在函数的类型中,并且仅在 ->
右侧的代码中可见。
Constr3
的类型为 DataType Int
,这意味着只要 DataType a
的值为 Constr3
,就知道 a ~ Int
。此信息也可以通过模式匹配来恢复。