Qual é a diferença entre ADTs, GADTs e tipos indutivos?

21

Alguém pode explicar a diferença entre:

  • Tipos de dados algébricos (com os quais estou bastante familiarizado)
  • Tipos de dados algébricos generalizados (o que os torna generalizados?)
  • Tipos indutivos (por exemplo, Coq)

(Tipos especialmente indutivos.) Obrigado.

ninjagecko
fonte

Respostas:

21

Os tipos de dados algébricos permitem definir tipos recursivamente. Concretamente, suponha que tenhamos o tipo de dados

datalist=Nil|ConsofN×list

O que isto significa é que é o mais pequeno conjunto gerado pela N i l e C o n s operadores. Podemos formalizar isso definindo o operador F ( X )listNilConsF(X)

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

e, em seguida, definir comolist

list=iNFi()

Um ADT generalizado é o que obtemos quando definimos um operador de tipo recursivamente. Por exemplo, podemos definir o seguinte construtor de tipos:

busha=Leafofa|Nestofbush(a×a)

bushaa2nnNest

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

Um tipo indutivo em Coq é essencialmente um GADT, onde os índices do operador de tipo não são restritos a outros tipos (como, por exemplo, Haskell), mas também podem ser indexados por valores da teoria de tipos. Isso permite que você forneça tipos para listas indexadas por comprimento e assim por diante.

Neel Krishnaswami
fonte
11
Obrigado. No entanto, isso não significa apenas que "tipo indutivo" é completamente sinônimo de "tipo dependente"?
Ninjagecko 08/03/12
4
@ Neel: Eu nunca vi tipos como os bushchamados GADTs. Eu os vi chamados tipos aninhados ou não regulares.
jbapple
3
Tipos aninhados são um caso especial de GADTs. O recurso crítico de um GADT é simplesmente o fato de ser uma definição recursiva de tipo superior. (As alterações nas RHS é basicamente açúcar sintáctica para a adição de uma igualdade tipo como um componente do construtor.)
Neel Krishnaswami
4
@ninjagecko: "Tipos indutivos" são tipos que recebem semântica como o ponto menos fixo de um construtor. Nem todos os tipos podem ser descritos dessa maneira (funções não podem e nem infinitos, como fluxos). Tipos dependentes descrevem tipos que permitem que os termos do programa ocorram neles (ou seja, os tipos podem "depender de" termos). Como Coq é uma teoria de tipos dependentes, os tipos indutivos que ele permite definir também são dependentes. Mas as teorias de tipos não dependentes também podem suportar tipos indutivos, e esses tipos indutivos não serão dependentes.
Neel Krishnaswami
2
@NeelKrishnaswami: Você gostaria de esclarecer sua resposta enumerando os "primeiros poucos menores" elementos dos tipos de bush a? Neste exemplo, é Nest Leaf(a) Leaf(a) Leaf(a) Leaf(a)ou Nest ((Nest Leaf(a) Leaf(a)) (Nest Leaf(a) Leaf(a)))como um exemplo do conjunto?
Ninjagecko 11/07/12
19

Considere tipos de dados algébricos, como:

data List a = Nil | Cons a (List a)

Os tipos de retorno de cada construtor em um tipo de dados são todos iguais: Nile Consambos retornam List a. Se permitirmos que os construtores retornem tipos diferentes, teremos um 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

Occupiedtem o tipo a -> NullableList a b -> NullableList a NonEmpty, enquanto Constem o tipo a -> List a -> List a. É importante notar que NonEmptyé um tipo, não um termo. Outro exemplo:

data Zero
data Succ n

data SizedList a t where
    Alone :: SizedList a Zero
    WithFriends :: a -> SizedList a n -> SizedList a (Succ n)

Tipos indutivos em linguagens de programação que possuem tipos dependentes permitem que os tipos de retorno dos construtores dependam dos valores (não apenas dos tipos) dos argumentos.

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).

Uma observação lateral: o GHC possui um mecanismo para tratar construtores de valor como construtores de tipo . Isso não é o mesmo que os tipos indutivos dependentes da Coq, mas diminui um pouco a carga sintática dos GADTs e pode levar a melhores mensagens de erro.

jbapple
fonte
Obrigado. "Tipos indutivos em linguagens de programação que possuem tipos dependentes" Como seria então um tipo indutivo em uma linguagem sem tipos dependentes e você pode ter tipos dependentes não indutivos (mas do tipo GADT)?
Ninjagecko 8/03/12