Was funktioniert
Wenn Sie die Definition des Fixpunkts in Listen innerhalb der Definition des Fixpunkts in Bäumen verschachteln, ist das Ergebnis gut typisiert. Dies ist ein allgemeines Prinzip, wenn Sie eine Rekursion in einem induktiven Typ verschachtelt haben, dh wenn die Rekursion einen Konstruktor wie folgt durchläuft list
.
Fixpoint size (t : LTree) : nat :=
let size_l := (fix size_l (l : list LTree) : nat :=
match l with
| nil => 0
| h::r => size h + size_l r
end) in
match t with Node l =>
1 + size_l l
end.
Oder wenn Sie es vorziehen, dies knapper zu schreiben:
Fixpoint size (t : LTree) : nat :=
match t with Node l =>
1 + (fix size_l (l : list LTree) : nat :=
match l with
| nil => 0
| h::r => size h + size_l r
end) l
end.
(Ich habe keine Ahnung, von wem ich es zuerst gehört habe; dies wurde sicherlich viele Male unabhängig voneinander entdeckt.)
Ein allgemeines Rekursionsprädikat
Im Allgemeinen können Sie das „richtige“ Induktionsprinzip LTree
manuell festlegen . Das automatisch erzeugte Induktionsprinzip LTree_rect
lässt die Hypothese in der Liste weg, da der Induktionsprinzip-Generator nur nicht verschachtelte streng positive Ereignisse vom Typ Induktion versteht.
LTree_rect =
fun (P : LTree -> Type) (f : forall l : list LTree, P (Node l)) (l : LTree) =>
match l as l0 return (P l0) with
| Node x => f x
end
: forall P : LTree -> Type,
(forall l : list LTree, P (Node l)) -> forall l : LTree, P l
Fügen wir die Induktionshypothese zu Listen hinzu. Um dies im rekursiven Aufruf zu erfüllen, nennen wir das Listeninduktionsprinzip und übergeben es dem kleineren Baum in der Liste.
Fixpoint LTree_rect_nest (P : LTree -> Type) (Q : list LTree -> Type)
(f : forall l, Q l -> P (Node l))
(g : Q nil) (h : forall t l, P t -> Q l -> Q (cons t l))
(t : LTree) :=
match t as t0 return (P t0) with
| Node l => f l (list_rect Q g (fun u r => h u r (LTree_rect_nest P Q f g h u)) l)
end.
Warum
Die Antwort auf das Warum liegt in den genauen Regeln für die Annahme rekursiver Funktionen. Diese Regeln sind zwangsläufig subtil, da es ein empfindliches Gleichgewicht zwischen dem Zulassen komplexer Fälle (wie dieser mit verschachtelter Rekursion im Datentyp) und Unzuverlässigkeit gibt. Das Coq-Referenzhandbuch enthält eine Einführung in die Sprache (die Berechnung induktiver Konstruktionen, die die Beweissprache von Coq ist), meist mit formal präzisen Definitionen. Wenn Sie jedoch die genauen Regeln für Induktion und Coinduktion wünschen, lesen Sie die Forschungsarbeiten. zu diesem Thema von Eduardo Giménez [1].
Fix
F i x fich{ f1: A1: = t1;f2: A2: = t2}
Γ1Γ2= ( X : L T r e e )= ( l : l i s tL T r e e )EIN1EIN2= n a t= n a tt1t2= C a s e ( x , L T r e e , λ y. G1( f2y) )= c a s e ( l , l i s tL T r e e ,λhr . G2( f1h ) ( f2r ) )
fjtichfich
- i = 1j = 2
l
t
size
- i = 2j = 1
h
l
size_l
- i = 2j = 2
r
l
size_l
Der Grund, warum h
strukturell nicht kleiner ist als l
laut Coq-Interpreter, ist mir nicht klar. Soweit ich aus den Diskussionen über die Coq-Club-Liste [1] [2] weiß, handelt es sich um eine Einschränkung des Dolmetschers, die grundsätzlich aufgehoben werden könnte, aber sehr sorgfältig, um Inkonsistenzen zu vermeiden.
Verweise
Cocorico, das nicht abschließende Coq-Wiki: Gegenseitige Induktion
Coq-Club Mailingliste:
Das Coq-Entwicklungsteam. Der Coq Proof Assistant: Referenzhandbuch . Version 8.3 (2010). [ web ] ch. 4 .
Eduardo Giménez. Codierung von geschützten Definitionen mit rekursiven Schemata . In Types'94: Types for Proofs and Programs , LNCS 996. Springer-Verlag, 1994. doi: 10.1007 / 3-540-60579-7_3 [ Springer ]
Eduardo Giménez. Strukturelle rekursive Definitionen in der Typentheorie . In ICALP'98: Proceedings of the 25. International Colloquium on Automata, Languages and Programming. Springer-Verlag, 1998. [ PDF ]