回答:
代数データ型を使用すると、型を再帰的に定義できます。具体的には、データ型があるとします
これは、がN i lおよびC o n s演算子によって生成される最小セットであることを意味します。演算子F (X )を定義することでこれを形式化できます
そして、それからl i s tを定義するをします
一般 ADTは、型定義するときに我々が得るものです演算子を再帰的に。たとえば、次の型コンストラクタを定義できます。
このタイプは、b u sの要素タプルである長さのS 2 Nいくつかのためのn我々が入るたびので、 NのE S Tコンストラクタ型引数がそれ自体と対になっています。したがって、固定小数点を取得する演算子を次のように定義できます。
Coqの帰納型は、本質的にGADTであり、型演算子のインデックスは他の型に制限されません(たとえば、Haskellなど)が、型理論の値によってインデックスを付けることもできます。これにより、長さのインデックス付きリストのタイプなどを指定できます。
bush
と呼ばれるタイプを見たことはありません。ネスト型または非正規型と呼ばれるものを見てきました。
bush a
か?この例では、それである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の構文上の負担をいくらか軽減し、エラーメッセージを改善することができます。