Considérons un type inductif qui a des occurrences récursives dans un emplacement imbriqué, mais strictement positif. Par exemple, des arbres à ramifications finies avec des nœuds utilisant une structure de données de liste générique pour stocker les enfants.
Inductive LTree : Set := Node : list LTree -> LTree.
La manière naïve de définir une fonction récursive sur ces arbres en récursant sur les arbres et les listes d'arbres ne fonctionne pas. Voici un exemple avec la size
fonction qui calcule le nombre de nœuds.
Fixpoint size (t : LTree) : nat := match t with Node l => 1 + (size_l l) end
with size_l (l : list LTree) : nat := match l with
| nil => 0
| cons h r => size h + size_l r
end.
Cette définition est mal formée (message d'erreur extrait):
Error:
Recursive definition of size_l is ill-formed.
Recursive call to size has principal argument equal to
"h" instead of "r".
Pourquoi la définition est-elle mal formée, même si elle r
est clairement un sous-terme de l
? Existe-t-il un moyen de définir des fonctions récursives sur une telle structure de données?
Si vous ne maîtrisez pas la syntaxe Coq: LTree
est un type inductif correspondant à la grammaire suivante.
Nous essayons de définir la size
fonction par induction sur des arbres et des listes. Dans OCaml, ce serait:
type t = Node of t list
let rec size = function Node l -> 1 + size_l l
and size_l = function [] -> 0
| h::r -> size h + size_l r
la source
Réponses:
Ce qui fonctionne
Si vous imbriquez la définition du point fixe sur des listes à l'intérieur de la définition du point fixe sur les arbres, le résultat est bien typé. Il s'agit d'un principe général lorsque vous avez imbriqué la récursivité dans un type inductif, c'est-à-dire lorsque la récursivité passe par un constructeur comme
list
.Ou si vous préférez écrire ceci de façon plus laconique:
(Je n'ai aucune idée de qui je l'ai entendu en premier; cela a certainement été découvert plusieurs fois de manière indépendante.)
Un prédicat général de récursivité
Plus généralement, vous pouvez définir
LTree
manuellement le principe d'induction «correct» . Le principe d'induction généré automatiquementLTree_rect
omet l'hypothèse de la liste, car le générateur de principe d'induction ne comprend que les occurrences strictement positives non imbriquées de type inductif.Ajoutons l'hypothèse d'induction sur les listes. Pour le remplir dans l'appel récursif, nous appelons le principe d'induction de liste et lui passons le principe d'induction d'arbre sur le plus petit arbre à l'intérieur de la liste.
Pourquoi
La réponse à cette question réside dans les règles précises d'acceptation des fonctions récursives. Ces règles sont forcément subtiles, car il y a un équilibre délicat entre autoriser des cas complexes (comme celui-ci, avec une récursion imbriquée dans le type de données) et des anomalies. Le manuel de référence Coq présente le langage (le calcul des constructions inductives, qui est le langage de preuve de Coq), principalement avec des définitions formellement précises, mais si vous voulez les règles exactes concernant l'induction et la coinduction, vous devrez consulter les articles de recherche, sur ce sujet Eduardo Giménez [1].
Fix
l
t
size
h
l
size_l
r
l
size_l
La raison pour laquelle
h
n'est pas structurellement plus petit quel
selon l'interprète Coq n'est pas claire pour moi. D'après ce que je comprends des discussions sur la liste des Coq-clubs [1] [2], il s'agit d'une restriction dans l'interprète, qui pourrait en principe être levée, mais très soigneusement pour éviter d'introduire une incohérence.Les références
Cocorico, le wiki Coq non terminal: induction mutuelle
Liste de diffusion Coq-Club:
L'équipe de développement Coq. Assistant Coq Proof: Manuel de référence . Version 8.3 (2010). [ web ] ch. 4 .
Eduardo Giménez. Codification des définitions gardées avec des schémas récursifs . Dans Types'94: Types pour les épreuves et les programmes , LNCS 996. Springer-Verlag, 1994. doi: 10.1007 / 3-540-60579-7_3 [ Springer ]
Eduardo Giménez. Définitions structurelles récursives en théorie des types . In ICALP'98: Actes du 25e Colloque international sur les automates, les langues et la programmation. Springer-Verlag, 1998. [ PDF ]
la source
C'est évidemment un problème spécifique à Coq car je pense qu'il existe de meilleures façons de le contourner avec d'autres assistants de preuve (je regarde Agda)
Au début, je pensais que ce
r
n'était pas reconnu comme étant structurellement plus petit parce que la structure ne concerne que la définition inductive actuellement gérée parFixpoint
: ce n'est donc pas un sous-LTree
terme même si c'est un sous-list
terme.Mais si vous développez le traitement de la liste, cela fonctionne:
Ou puisque la fonction auxiliaire existe déjà dans la bibliothèque standard:
Pour être honnête, je ne sais pas pourquoi ceux-ci sont acceptés par Coq, mais je suis sûr qu'ils le sont.
Il existe également une solution qui fonctionne plus souvent et pas seulement pour les listes: définir un type inductif autonome. Dans ce cas, vous pouvez définir votre
size
fonction manuellement. (avec deux points fixes)Notez que si vous rencontrez des problèmes pour des définitions inductives plus complexes, vous pouvez utiliser un argument de diminution de taille. C'est possible mais lourd pour ce problème (et j'oserais dire pour la plupart des problèmes)
la source