Dérivation claire et intuitive du combinateur à virgule fixe (combinateur Y)?

28

Le combinateur à virgule fixe FIX (alias le combinateur Y) dans le calcul lambda (non typé) ( λ ) est défini comme:

λf.(λx.f (λy.x x y)) (λx.f (λy.x x y))

Je comprends son objet et je peux tracer parfaitement l'exécution de son application; Je voudrais comprendre comment dériver FIX des premiers principes .

Voici ce que j'obtiens quand j'essaye de le dériver moi-même:

  1. FIX est une fonction: FIXλ
  2. FIX prend une autre fonction, , pour la rendre récursive: FIXλ f . fλf.
  3. Le premier argument de la fonction est le "nom" de la fonction, utilisé là où une application récursive est destinée. Par conséquent, toutes les apparences du premier argument de doivent être remplacées par une fonction, et cette fonction doit attendre le reste des arguments de (supposons simplement que prend un argument): FIXf ffffλ f . F ( λ y . Y )fλf.f (λy.y)

C'est là que je ne sais pas "faire un pas" dans mon raisonnement. Les petites ellipses indiquent où mon FIX manque quelque chose (bien que je ne puisse le savoir qu'en le comparant au "vrai" FIX).

J'ai déjà lu Types et langages de programmation , qui ne tente pas de le dériver directement, et renvoie plutôt le lecteur à The Little Schemer pour une dérivation. J'ai lu cela aussi, et sa "dérivation" n'était pas si utile. De plus, il s'agit moins d'une dérivation directe que d'une utilisation d'un exemple très spécifique et d'une tentative ad hoc d'écrire une fonction récursive appropriée dans .λ

BlueBomber
la source
1
Ce message pourrait être utile. En général, je pense que le simple fait de parcourir et de calculer plusieurs itérations du combinateur est utile pour comprendre pourquoi cela fonctionne.
Xodarap
2
Il existe plusieurs combinateurs à virgule fixe différents. Peut-être que les gens ont juste joué avec des combinateurs jusqu'à ce qu'ils tombent sur eux.
Yuval Filmus
@YuvalFilmus, c'est ce que mes recherches et la réponse à cette question commencent à me faire réfléchir. Mais je pense toujours qu'il serait instructif de "voir" comment les combinateurs sont formés logiquement, une compétence qui serait particulièrement utile lorsque, par exemple, on essaie de construire un nouveau combinateur.
BlueBomber
Lisez le chapitre 9 dans "The Little Lisper", de Daniel P. Friedman (ou "The Little Schemer").
user18199
2
Le PO semble indiquer qu'ils l'ont déjà lu.
Raphael

Réponses:

29

Je n'ai lu cela nulle part, mais voici comment je pense que aurait pu être dérivé:Y

Ayons une fonction r récursive , peut-être une factorielle ou autre chose comme ça. De manière informelle, nous définissons comme un terme pseudo-lambda où apparaît dans sa propre définition:f ffff

f=ff

Tout d'abord, nous réalisons que l'appel récursif peut être factorisé comme paramètre:

f=(λr.(rr))Mf

Maintenant, nous pourrions définir si nous avions seulement un moyen de le passer comme argument à lui-même. Ce n'est pas possible, bien sûr, car nous n'avons pas de à portée de main. Ce que nous avons à portée de main est . Puisque contient tout ce dont nous avons besoin pour définir , nous pouvons essayer de passer comme argument au lieu de et essayer de reconstruire partir de lui plus tard à l'intérieur. Notre première tentative ressemble à ceci:f M M f M f fffMMfMff

f=(λr.(rr))M(λr.(rr))M

Cependant, ce n'est pas complètement correct. Avant, obtenu est substitué à à l' intérieur . Mais maintenant, nous passons place. Nous devons corriger en quelque sorte tous les endroits où nous utilisons pour que reconstruisent de . En fait, ce n'est pas difficile du tout: maintenant que nous savons que , partout où nous utilisons nous le remplaçons simplement par .r M M r f M f = M M r ( r r )frMMrfMf=MMr(rr)

f=(λr.((rr)(rr)))M(λr.((rr)(rr)))M

Cette solution est bonne, mais nous avons dû modifier intérieur. Ce n'est pas très pratique. Nous pouvons le faire plus élégamment sans avoir à modifier en introduisant un autre qui envoie à son argument appliqué à lui-même: En exprimant comme nous obtenonsM λ M M λ x . M ( x x )MMλMMλx.M(xx)

f=(λx.(λr.(rr))M(xx))(λx.(λr.(rr))M(xx))

De cette façon, lorsque est substitué à , est substitué à , qui est par définition égal à . Cela nous donne une définition non récursive de , exprimée en terme lambda valide!x M M r f fMxMMrff

La transition vers est maintenant facile. Nous pouvons prendre un terme lambda arbitraire au lieu de et effectuer cette procédure dessus. Nous pouvons donc factoriser et définirM MYMM

Y=λm.(λx.m(xx))(λx.m(xx))

En effet, réduit à tel que nous l'avons défini.fYMf


Remarque: J'ai dérivé tel qu'il est défini dans la littérature. Le combinateur que vous avez décrit est une variante de pour appel par valeur langues, parfois aussi appelé . Voir cet article Wikipedia .Y ZYYZ

Petr Pudlák
la source
1
L'intuition manque mais, apparemment évidente que votre excellente réponse m'a donné est qu'une fonction récursive elle - même a besoin comme argument, donc nous commençons avec une hypothèse que la fonction aura la forme pour certains . Ensuite, lorsque nous construisons , nous utilisons cette affirmation selon laquelle est défini comme l'application de quelque chose à lui-même en interne dans , par exemple, en appliquant à dans votre réponse, qui est par définition égale à . Fascinant! X X f X x x ff=X(X)XXfXxxf
BlueBomber
11

Comme l'a souligné Yuval, il n'y a pas qu'un seul opérateur à virgule fixe. Il y a beaucoup d'entre eux. En d'autres termes, l'équation du théorème à virgule fixe n'a pas de réponse unique. Vous ne pouvez donc pas en dériver l'opérateur.

C'est comme demander comment les gens dérivent comme solution pour . Ils ne le font pas! L'équation n'a pas de solution unique.x = y(x,y)=(0,0)x=y


Juste au cas où ce que vous voulez savoir, c'est comment le premier théorème du point fixe a été découvert. Permettez-moi de dire que je me suis également demandé comment ils étaient parvenus aux théorèmes de point fixe / récursivité lorsque je les ai vus pour la première fois. Cela semble si ingénieux. Particulièrement sous la forme de théorie de calculabilité. Contrairement à ce que dit Yuval, il n'est pas vrai que les gens jouent jusqu'à ce qu'ils trouvent quelque chose. Voici ce que j'ai trouvé:

Pour autant que je m'en souvienne, le théorème est à l'origine dû à SC Kleene. Kleene est venu avec le théorème du point fixe d'origine en récupérant la preuve de l'incohérence du calcul lambda original de Church. Le calcul lambda original de Church souffrait d'un paradoxe de type Russel. Le calcul lambda modifié a évité le problème. Kleene a étudié la preuve de l'incohérence probablement pour voir comment le calcul lambda modifié souffrirait d'un problème similaire et a transformé la preuve de l'incohérence en un théorème utile dans le calcul lambda modifié. Par son travail sur l'équivalence du calcul lambada avec d'autres modèles de calcul (machines de Turing, fonctions récursives, etc.), il l'a transféré à d'autres modèles de calcul.


Comment dériver l'opérateur que vous pourriez demander? Voici comment je garde cela à l'esprit. Le théorème à virgule fixe consiste à supprimer l'auto-référence.

Tout le monde connaît le paradoxe du menteur:

Je suis un repaire.

Ou sous une forme plus linguistique:

Cette phrase est fausse.

Maintenant, la plupart des gens pensent que le problème avec cette phrase est lié à l'auto-référence. Ce n'est pas! L'auto-référence peut être éliminée (le problème est avec la vérité, une langue ne peut pas parler de la vérité de ses propres phrases en général, voir l'indéfinissabilité du théorème de vérité de Tarski ). Le formulaire où l'auto-référence est supprimée est le suivant:

Si vous écrivez deux fois la citation suivante, la deuxième fois entre guillemets, la phrase résultante est fausse: "Si vous écrivez deux fois la citation suivante, la deuxième fois entre guillemets, la phrase résultante est fausse:"

Pas d'auto-référence, nous avons des instructions sur la façon de construire une phrase, puis d'en faire quelque chose. Et la phrase qui se construit est égale aux instructions. Notez que dans -calculus, nous n'avons pas besoin de guillemets car il n'y a pas de distinction entre les données et les instructions.λ

Maintenant, si nous analysons cela, nous avons où est les instructions pour construire et y faire quelque chose.MMMxxx

Mx=f(xx)

Donc est et nous avonsMλx.f(xx)

MM=(λx.f(xx))(λx.f(xx))

C'est pour un fixe . Si vous voulez en faire un opérateur, nous ajoutons simplement et nous obtenons :fλfY

Y=λf.(MM)=λf.((λx.f(xx))(λx.f(xx)))

Je viens donc de garder à l' esprit le paradoxe sans autoréférence et qui me permet de comprendre ce que est sur le point .Y

Kaveh
la source
3

Vous devez donc définir un combinateur à virgule fixe

fix f = f (fix f)
      = f (f (fix f))
      = f (f (f ... ))

mais sans récursivité explicite. Commençons par le combinateur irréductible le plus simple

omega = (\x. x x) (\x. x x)
      = (\x. x x) (\x. x x)
      = ...

La xpremière lambda est remplacée à plusieurs reprises par la deuxième lambda. Une simple conversion alpha rend ce processus plus clair:

omega =  (\x. x x) (\x. x x)
      =α (\x. x x) (\y. y y)
      =β (\y. y y) (\y. y y)
      =α (\y. y y) (\z. z z)
      =β (\z. z z) (\z. z z)

C'est-à-dire que la variable dans la première lambda disparaît toujours. Donc, si nous ajoutons un fau premier lambda

(\x. f (x x)) (\y. y y)

le fbob up

f ((\y. y y) (\y. y y))

Nous avons le omegados. Il devrait être clair maintenant, que si nous ajoutons un fà la deuxième lambda, alors le fapparaîtra dans la première lambda et ensuite il montera:

Y f = (\x. x x)     (\x. f (x x))
      (\x. f (x x)) (\x. f (x x)) -- the classical definition of Y

Puisque

(\x. s t) z = s ((\x. t) z), if `x' doesn't occur free in `s'

nous pouvons réécrire l'expression comme

f ((\x. x x) (\x. f (x x))

ce qui est juste

f (Y f)

et nous avons notre équation Y f = f (Y f). Le Ycombinateur est donc essentiellement

  1. doubler le f
  2. faire le premier fenroulé
  3. répéter
user3237465
la source
2

Vous avez peut-être vu l'exemple classique d'une équation sans forme normale:

(λx.xx)(λx.xx)(λx.xx)(λx.xx)

Une équation similaire est suggérée par celle pour la récursivité générale:

(A)(λx.R(xx))(λx.R(xx)) R( (λx.R(xx))(λx.R(xx)) )R(R( (λx.R(xx))(λx.R(xx)) ))

(A) est un moyen d'écrire des équations récursives générales dans le calcul lambda (au-delà du récursif primitif). Alors, comment résolvez-vous l'équation ? Branchez dans dans l'équation ci-dessus pour obtenir:Yf=f(Yf)fR

Y = λ f . ( λ x . f ( x x ) ) ( λ x . f ( x x ) )

Yf=(λx.f(xx))(λx.f(xx))
Y=λf.(λx.f(xx))(λx.f(xx))
DanielV
la source