Eh bien, quelque chose connu sous le nom de paramétricité nous dit que si nous considérons le sous-ensemble pur de ML (c'est-à-dire pas de récursion infinie, refet toutes ces choses étranges), il n'y a aucun moyen de définir une fonction avec ce type autre que celle renvoyant le vide liste.
Tout a commencé avec l'article de Wadler « Theorems for free! ". Cet article, en gros, nous dit deux choses:
- Si nous considérons des langages de programmation qui remplissent certaines conditions, nous pouvons en déduire quelques théorèmes sympas simplement en regardant la signature de type d'une fonction polymorphe (c'est ce qu'on appelle le théorème de paramétrie).
- ML (sans récursion infinie
refet tout ce truc bizarre) remplit ces conditions.
De l'paramétricité Théorème nous savons que si nous avons une fonction f : 'a list -> 'b list, puis pour tous 'a, 'b, 'c, 'det pour toutes les fonctions g : 'a -> 'c, h : 'b -> 'dnous avons:
map h ∘ f = f ∘ map g
(Remarque, fà gauche a le type 'a list -> 'b listet fà droite est 'c list -> 'd list.)
Nous sommes libres de choisir ce que gnous voulons, alors laissez 'a = 'cet g = id. Or depuis map id = id(facile à prouver par récurrence sur la définition de map), on a:
map h ∘ f = f
Maintenant, laissez 'b = 'd = boolet h = not. Supposons que pour certains, zs : bool listcela arrive f zs ≠ [] : bool list. Il est clair que map not ∘ f = fcela ne tient pas , car
(map not ∘ f) zs ≠ f zs
Si le premier élément de la liste à droite est true, alors à gauche le premier élément est falseet vice versa!
Cela signifie que notre hypothèse est fausse et f zs = []. Avons-nous fini? Non.
Nous avons supposé que 'best bool. Nous avons montré que lorsque fest invoqué avec type f : 'a list -> bool listpour any 'a, fdoit toujours renvoyer la liste vide. Se peut-il que lorsque nous appelons f, f : 'a list -> unit listcela renvoie quelque chose de différent? Notre intuition nous dit que c'est un non-sens: nous ne pouvons tout simplement pas écrire en ML pur une fonction qui retourne toujours la liste vide quand nous voulons qu'elle nous donne une liste de booléens et pourrait retourner une liste non vide sinon! Mais ce n'est pas une preuve.
Ce que nous voulons dire, c'est que fc'est uniforme : s'il retourne toujours la liste vide pour bool list, alors il doit retourner la liste vide pour unit listet, en général, tout 'a list. C'est exactement le sujet du deuxième point de la liste à puces au début de ma réponse.
Le papier nous dit qu'en ML fdoit prendre des valeurs liées à celles qui sont liées . Je n'entre pas dans les détails des relations, il suffit de dire que les listes sont liées si et seulement si elles ont des longueurs égales et leurs éléments sont liés par paires (c'est-à-dire, [x_1, x_2, ..., x_m]et [y_1, y_2, ..., y_n]sont liés si et seulement si m = net x_1sont liés à y_1et x_2est lié à y_2et ainsi de suite). Et la partie amusante est, dans notre cas, puisqu'elle fest polymorphe, on peut définir n'importe quelle relation sur les éléments des listes!
Choisissons 'a-en 'bet regardons f : 'a list -> 'b list. Regardez maintenant f : 'a list -> bool list; nous avons déjà montré que dans ce cas fretourne toujours la liste vide. Nous postulons maintenant que tous les éléments de 'asont liés à eux-mêmes (rappelez-vous, nous pouvons choisir n'importe quelle relation que nous voulons), cela implique que tout zs : 'a listest lié à lui-même. Comme nous le savons, fprend des valeurs liées à celles liées, cela signifie que f zs : 'b listest lié à f zs : bool list, mais la deuxième liste a une longueur égale à zéro, et puisque la première est liée à elle, elle est également vide.
Pour être complet, je mentionnerai qu'il y a une section sur l'impact de la récursivité générale (non-résiliation possible) dans l'article original de Wadler, et il y a aussi un article explorant les théorèmes libres en présence de seq.