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, ref
et 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
ref
et 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
, 'd
et pour toutes les fonctions g : 'a -> 'c
, h : 'b -> 'd
nous avons:
map h ∘ f = f ∘ map g
(Remarque, f
à gauche a le type 'a list -> 'b list
et f
à droite est 'c list -> 'd list
.)
Nous sommes libres de choisir ce que g
nous voulons, alors laissez 'a = 'c
et 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 = bool
et h = not
. Supposons que pour certains, zs : bool list
cela arrive f zs ≠ [] : bool list
. Il est clair que map not ∘ f = f
cela 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 false
et vice versa!
Cela signifie que notre hypothèse est fausse et f zs = []
. Avons-nous fini? Non.
Nous avons supposé que 'b
est bool
. Nous avons montré que lorsque f
est invoqué avec type f : 'a list -> bool list
pour any 'a
, f
doit toujours renvoyer la liste vide. Se peut-il que lorsque nous appelons f
, f : 'a list -> unit list
cela 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 f
c'est uniforme : s'il retourne toujours la liste vide pour bool list
, alors il doit retourner la liste vide pour unit list
et, 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 f
doit 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 = n
et x_1
sont liés à y_1
et x_2
est lié à y_2
et ainsi de suite). Et la partie amusante est, dans notre cas, puisqu'elle f
est polymorphe, on peut définir n'importe quelle relation sur les éléments des listes!
Choisissons 'a
-en 'b
et regardons f : 'a list -> 'b list
. Regardez maintenant f : 'a list -> bool list
; nous avons déjà montré que dans ce cas f
retourne toujours la liste vide. Nous postulons maintenant que tous les éléments de 'a
sont liés à eux-mêmes (rappelez-vous, nous pouvons choisir n'importe quelle relation que nous voulons), cela implique que tout zs : 'a list
est lié à lui-même. Comme nous le savons, f
prend des valeurs liées à celles liées, cela signifie que f zs : 'b list
est 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
.