Answers:
代数数据类型使您可以递归定义类型。具体来说,假设我们具有数据类型
这意味着是和运算符生成的最小集合。我们可以通过定义运算符来形式化它Ñ 我升Ç Ò Ñ 小号 ˚F (X )
然后将定义为
一个广义 ADT是我们所得到的,当定义一个类型运营商递归。例如,我们可以定义以下类型构造函数:
此类型表示的元素是长度为 s的元组,持续,因为每次我们进入构造函数时,type参数都会与自身配对。因此,我们可以定义一个固定点为:a 2 n n N e s t
Coq中的归纳类型本质上是GADT,其中类型运算符的索引不限于其他类型(例如,在Haskell中),还可以通过类型理论的值进行索引。这使您可以为长度索引列表指定类型,等等。
bush
GADT 这样的类型。我见过它们称为嵌套或非常规类型。
bush a
?在这个例子中,是it Nest Leaf(a) Leaf(a) Leaf(a) Leaf(a)
还是Nest ((Nest Leaf(a) Leaf(a)) (Nest Leaf(a) Leaf(a)))
作为集合的一个例子?
考虑代数数据类型,例如:
data List a = Nil | Cons a (List a)
返回类型的数据类型的每个构造都是一样的:Nil
和Cons
都返回List a
。如果我们允许构造函数返回不同的类型,则我们有GADT:
data Empty -- this is an empty data declaration; Empty has no constructors
data NonEmpty
data NullableList a t where
Vacant :: NullableList a Empty
Occupied :: a -> NullableList a b -> NullableList a NonEmpty
Occupied
有类型a -> NullableList a b -> NullableList a NonEmpty
,而Cons
有类型a -> List a -> List a
。重要的是要注意这NonEmpty
是一种类型,而不是术语。另一个例子:
data Zero
data Succ n
data SizedList a t where
Alone :: SizedList a Zero
WithFriends :: a -> SizedList a n -> SizedList a (Succ n)
具有依赖类型的编程语言中的归纳类型允许构造函数的返回类型依赖于参数的值(而不仅仅是类型)。
Inductive Parity := Even | Odd.
Definition flipParity (x:Parity) : Parity :=
match x with
| Even => Odd
| Odd => Even
end.
Fixpoint getParity (x:nat) : Parity :=
match x with
| 0 => Even
| S n => flipParity (getParity n)
end.
(*
A ParityNatList (Some P) is a list in which each member
is a natural number with parity P.
*)
Inductive ParityNatList : option Parity -> Type :=
Nil : forall P, ParityNatList P
| Cons : forall (x:nat) (P:option Parity),
ParityNatList P -> ParityNatList
(match P, getParity x with
| Some Even, Even => Some Even
| Some Odd, Odd => Some Odd
| _, _ => None
end).
附带说明:GHC具有将值构造函数视为类型构造函数的机制。这与Coq所具有的从属归纳类型不同,但是它在某种程度上减轻了GADT的语法负担,并且可以导致更好的错误消息。