ADT、GADT、および誘導型の違いは何ですか?


21

誰でも次の違いを説明できるかもしれません:

  • 代数データ型(私はかなりよく知っています)
  • 一般化された代数データ型(それらを一般化する理由)
  • 誘導型(例:Coq)

(特に誘導型。)ありがとう。

回答:


21

代数データ型を使用すると、型を再帰的に定義できます。具体的には、データ型があるとします

datalist=Nil|ConsofN×list

これは、N i lおよびC o n s演算子によって生成される最小セットであることを意味します。演算子F X )を定義することでこれを形式化できますlistNilConsF(X)

F(X)=={Nil}{Cons(n,x)|nNxX}

そして、それからl i s tを定義するlistをします

list=iNFi()

一般 ADTは、型定義するときに我々が得るものです演算子を再帰的に。たとえば、次の型コンストラクタを定義できます。

busha=Leafofa|Nestofbush(a×a)

このタイプは、b u sの要素タプルである長さのS 2 Nいくつかのためのn我々が入るたびので、 NのE S Tコンストラクタ型引数がそれ自体と対になっています。したがって、固定小数点を取得する演算子を次のように定義できます。bushaa2nnNest

F(R)=λX.{Leaf(x)|xX}{Nest(v)|vR(X)}

Coqの帰納型は、本質的にGADTであり、型演算子のインデックスは他の型に制限されません(たとえば、Haskellなど)が、型理論のによってインデックスを付けることもできます。これにより、長さのインデックス付きリストのタイプなどを指定できます。


1
ありがとうございました。しかし、それは「依存型」と完全に同義の「誘導型」を意味するのではないでしょうか?
ninjagecko

4
@Neel:GADT bushと呼ばれるタイプを見たことはありません。ネスト型または非正規型と呼ばれるものを見てきました。
jbapple

3
ネストされたタイプは、GADTの特殊なケースです。GADTの重要な特徴は、単純にそれがより高い種類の再帰的な定義であることです。(rhsへの変更は、基本的にコンストラクターのコンポーネントとして型の平等を追加するための構文上の砂糖です。)
ニールクリシュナスワミ

4
@ninjagecko:「帰納的な型」は、コンストラクターの最小固定点としてセマンティクスが与えられた型です。すべてのタイプをこのように記述できるわけではありません(関数では記述できません。また、ストリームなどの無限のタイプでも記述できません)。依存型は、プログラム用語が出現することを許可する型を記述します(つまり、型は用語に「依存する」ことができます)。Coqは依存型理論であるため、Coqで定義できる帰納型も依存します。しかし、非依存型の理論は帰納型もサポートすることができ、それらの帰納型は依存しません。
ニールクリシュナスワミ

2
@NeelKrishnaswami:タイプの「最初の数個の最小」要素を列挙することで答えを明確にするほど親切になりますbush aか?この例では、それであるNest Leaf(a) Leaf(a) Leaf(a) Leaf(a)、またはNest ((Nest Leaf(a) Leaf(a)) (Nest Leaf(a) Leaf(a)))セットの一例として?
-ninjagecko

19

次のような代数データ型を検討してください。

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の構文上の負担をいくらか軽減し、エラーメッセージを改善することができます。


ありがとうございました。「依存型を持つプログラミング言語の誘導型」誘導型は、依存型のない言語ではどのように見えますか。また、非誘導(ただしGADTのような)依存型を持つことはできますか?
ninjagecko
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.