Polimorfismo e tipi di dati induttivi


10

Sono curioso. Ho lavorato su questo tipo di dati in OCaml :

type 'a exptree =
  | Epsilon
  | Delta of 'a exptree * 'a exptree
  | Omicron of 'a
  | Iota of 'a exptree exptree

Che può essere manipolato usando funzioni ricorsive tipizzate in modo esplicito (una funzione che è stata aggiunta abbastanza di recente). Esempio:

let rec map : 'a 'b. ('a -> 'b) -> 'a exptree -> 'b exptree =
  fun f ->
    begin function
    | Epsilon -> Epsilon
    | Delta (t1, t2) -> Delta (map f t1, map f t2)
    | Omicron t -> Omicron (f t)
    | Iota tt -> Iota (map (map f) tt)
    end

Ma non sono mai stato in grado di definirlo in Coq :

Inductive exptree a :=
  | epsilon : exptree a
  | delta : exptree a -> exptree a -> exptree a
  | omicron : a -> exptree a
  | iota : exptree (exptree a) -> exptree a
.

Coq sta piagnucolando. Non gli piace l'ultimo costruttore e dice qualcosa che non capisco completamente o con cui sono d'accordo:

Error: Non strictly positive occurrence of "exptree" in "exptree (exptree a) -> exptree a".

Quello che posso capire è che i tipi induttivi che usano una negazione all'interno della loro definizione come type 'a term = Constructor ('a term -> …)sono respinti, perché porterebbero a brutte bestie non ben fondate come i termini (non tipizzati) λ. Tuttavia, questo particolare exptreetipo di dati sembra abbastanza innocuo: osservando la sua definizione OCaml , il suo argomento 'anon viene mai usato in posizioni negative.

Sembra che Coq sia troppo esagerato qui. Quindi c'è davvero un problema con questo particolare tipo di dati induttivo? O Coq potrebbe essere leggermente più permissivo qui?

Inoltre, che dire degli altri assistenti di prova, sono in grado di far fronte a una definizione così induttiva (in modo naturale)?

Risposte:


9

Questo è apparso più volte sulla mailing list di Coq, ma non ho mai visto una risposta definitiva. Coq non è così generale come potrebbe essere; le regole di (Coquand, 1990) e (Giménez, 1998) (e la sua tesi di dottorato) sono più generali e non richiedono una rigida positività. La positività non è abbastanza, tuttavia, quando esci Set; questo esempio è emerso in diverse discussioni :

Inductive Big : Type := B : ((B -> Prop) -> Prop) -> Big.

Con semplici strutture di dati come la tua, il tipo induttivo non causerebbe problemi se non quello di rendere l'implementazione più complessa.

Esiste un modo generale per definire tipi come questo definito come punto fisso di un polinomio:

F=ϵ+δ(F×F)+οid+FF

Invece di tentare di definire la funzione , definisci la famiglia di tipi . Questo significa aggiungere un parametro intero al tipo che codifica il numero di autocomposizioni ( , , , ecc.) e un costruttore di iniezione supplementare per trasformare in .exptree:aexptree(a)exptree,exptreeexptree,exptreeexptreeexptree,exptree0(a)=aexptree1(a)=exptree(a)a e x p t r e e 0 ( a ) = aexptree2(a)=exptree(exptree(a))aexptree0(a)=a

Inductive et : nat -> Type -> Type :=
  | alpha : forall a, a -> et 0 a                      (*injection*)
  | omicron : forall n a, et n a -> et (S n) a         (**)
  | epsilon : forall (S n) a, et (S n) a
  | delta : forall n a, et (S n) a -> et (S n) a -> et (S n) a
  | iota : forall n a, et (S (S n)) a -> et (S n) a
.

Puoi procedere per definire i valori e lavorarci sopra. Coq sarà spesso in grado di inferire l'esponente. Set Implicit Argumentsrenderebbe queste definizioni più belle.

Definition exptree := et 1.
Definition et1 : exptree nat :=
  delta _ _ (omicron _ _ (alpha _ 42)) (epsilon _ _).
Definition et2 : exptree nat := iota _ _ (omicron _ _ et1).

Puoi preferire ridurre l'argomento di 1, quindi exptreeè così et 0. Questo rimuove molto S ndalla definizione, il che può rendere più semplici alcune prove, ma richiede la divisione del caso iniziale dal caso di ricorrenza in ogni costruttore che accetta una in un argomento (invece di aggiungere un singolo costruttore di iniezione per ). In questo esempio, c'è un solo costruttore da dividere, quindi questa dovrebbe essere una buona scelta.aaa

Inductive et : nat -> Type -> Type :=
  | omicron_0 : forall a, a -> et 0 a
  | omicron_S : forall n a, et n a -> et (S n) a
  | epsilon : forall n a, et n a
  | delta : forall n a, et n a -> et n a -> et n a
  | iota : forall n a, et (S n) a -> et n a
.
Definition exptree := et 0.
Definition et1 : exptree nat :=
  delta _ _ (omicron_0 _ 42) (epsilon _ _).
Definition et2 : exptree nat :=
  (iota _ _ (omicron_S _ _ et1)).

Penso che questo sia lo stesso principio proposto in una forma più generale da Ralph Mattes .

Riferimenti

Thierry Coquand e Christine Paulin. Tipi definiti induttivamente . Negli atti di COLOG'88 , LNCS 417, 1990. [ Springer ] [ Google ]

Eduardo Giménez. Definizioni ricorsive strutturali nella teoria dei tipi . In ICALP'98: Atti del 25 ° Colloquio internazionale su automi, lingue e programmazione. Springer-Verlag, 1998. [ PDF ]


8

Ralph Matthes descrive come simulare tipi come questo in Coq in "Una datastruttura per poteri alterati" ( codice , carta ).


6

Una delle prime cose che Coq fa è costruire il principio di induzione associato al tipo induttivo che hai appena definito e comprendere il principio di induzione sottostante è un buon esercizio.

Ad esempio O : nat | S : nat -> natgenererà il principio di induzione P O -> (∀ n, P n -> P (S n)) -> ∀ n, P n.

Quale sarebbe il principio di induzione corrispondente iota? Sembra che non ci sia predicato Pche sarebbe in grado di parlare P te P (iota t), perché dovrebbe parlare exptree a, exptree (exptree a), exptree (exptree (exptree a))...

Inoltre Omicronfa la stessa cosa ma il tipo è più piccolo ogni volta. Dovresti pensare che avere un riferimento sia a un tipo più piccolo che a un tipo più grande renderebbe le cose disordinate. (Detto questo, Omicronè la strada giusta)

Questo non è il criterio esatto che dice perché la definizione non dovrebbe essere accettata, ma questo spiega perché mi sembra sbagliato.

exptreesembra che tu stia costruendo una grammatica per le espressioni, cosa che generalmente non è così ricorsiva. Vuoi un aiuto con questo?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.