¿Derivación clara e intuitiva del combinador de punto fijo (combinador Y)?

28

El combinador de punto fijo FIX (también conocido como el combinador Y) en el cálculo lambda ( tipo) ( ) se define como:λ

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

Entiendo su propósito y puedo rastrear la ejecución de su aplicación perfectamente bien; Me gustaría entender cómo derivar FIX de los primeros principios .

Aquí es lo más lejos que puedo llegar cuando intento derivarlo yo mismo:

  1. FIX es una función: FIX λ
  2. FIX toma otra función, f , para hacerla recursiva: FIX λf.
  3. El primer argumento de la función f es el "nombre" de la función, utilizada donde se pretende una aplicación recursiva. Por lo tanto, todas las apariencias del primer argumento de f deberían ser reemplazadas por una función, y esta función debería esperar el resto de los argumentos de f (supongamos que f toma un argumento): FIX λf.f (λy.y)

Aquí es donde no sé cómo "dar un paso" en mi razonamiento. Las pequeñas elipses indican dónde falta algo en mi FIX (aunque solo puedo saberlo comparándolo con el FIX "real").

Ya he leído Tipos y lenguajes de programación , que no intenta derivarlo directamente, y en su lugar refiere al lector a The Little Schemer para una derivación. También lo he leído, y su "derivación" no fue tan útil. Además, es menos una derivación directa y más un uso de un ejemplo muy específico y un intento ad-hoc de escribir una función recursiva adecuada en λ .

BlueBomber
fuente
1
Esta publicación puede ser útil. En general, creo que solo pasar y calcular varias iteraciones del combinador es útil para descubrir por qué funciona.
Xodarap
2
Hay varios combinadores de punto fijo diferentes. Tal vez la gente solo jugaba con combinadores hasta que se toparon con ellos.
Yuval Filmus
@YuvalFilmus, eso es lo que mi investigación y la respuesta a esta pregunta están empezando a hacerme pensar. Pero sigo pensando que sería instructivo "ver" cómo se forman lógicamente el (los) combinador (es), una habilidad que sería especialmente útil cuando, por ejemplo, intente construir un nuevo combinador.
BlueBomber
Lea el capítulo 9 en "The Little Lisper", de Daniel P. Friedman (o "The Little Schemer").
user18199
2
El OP parece indicar que ya lo han leído.
Raphael

Respuestas:

29

No he leído esto en ninguna parte, pero así es como creo que podría haberse derivado:Y

Tengamos una función recursiva , quizás un factorial o algo así. Informalmente, definimos f como término pseudo-lambda donde f aparece en su propia definición:fff

f=ff

Primero, nos damos cuenta de que la llamada recursiva se puede factorizar como un parámetro:

f=(λr.(rr))Mf

Ahora podríamos definir si solo tuviéramos una manera de pasarlo como un argumento para sí mismo. Esto no es posible, por supuesto, porque no tenemos f a mano. Lo que tenemos a la mano es M . Como M contiene todo lo que necesitamos para definir f , podemos tratar de pasar M como argumento en lugar de f e intentar reconstruir f a partir de él más adelante. Nuestro primer intento se ve así:ffMMfMff

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

Sin embargo, esto no es completamente correcto. Antes, consiguió sustituido por r dentro de M . Pero ahora pasamos M en su lugar. Tenemos que arreglar de alguna manera todos los lugares en los que usamos r para que reconstruyen f de M . En realidad, esto no es nada difícil: ahora que sabemos que f = M M , en todas partes donde usamos r simplemente lo reemplazamos por ( r r ) .frMMrfMf=MMr(rr)

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

Esta solución es buena, pero tuvimos que alterar dentro. Esto no es muy conveniente. Podemos hacer esto de manera más elegante sin tener que modificar M introduciendo otro λ que envía a M su argumento aplicado a sí mismo: Expresando M como λ x . M ( x x ) obtenemosMMλMMλx.M(xx)

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

De esta manera, cuando se sustituye por x , M M se sustituye por r , que es, por definición, igual a f . ¡Esto nos da una definición no recursiva de f , expresada como un término lambda válido!MxMMrff

La transición a ahora es fácil. Podemos tomar un término lambda arbitrario en lugar de M y realizar este procedimiento en él. Entonces podemos factorizar M y definirYMM

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

De hecho, reduce a f como lo definimos.YMf


Nota: He derivado como se define en la literatura. El combinador que has descrito es una variante de Y de llamada por valor de idiomas, a veces también llamado Z . Ver este artículo de Wikipedia .YYZ

Petr Pudlák
fuente
1
La falta -pero-aparentemente obvia la intuición de que su excelente respuesta me dio es que una función recursiva debe a sí mismo como un argumento, por lo que empezar con la suposición de que la función tendrá la forma para algunos X . Luego, a medida que construimos X , hacemos uso de esa afirmación de que f se define como la aplicación interna de algo a sí mismo en X , por ejemplo, aplicando x a x en su respuesta, que por definición es igual a f . ¡Fascinante! f=X(X)XXfXxxf
BlueBomber
11

Como Yuval ha señalado, no hay un solo operador de punto fijo. Hay muchos de ellos. En otras palabras, la ecuación para el teorema del punto fijo no tiene una respuesta única. Por lo tanto, no puede derivar el operador de ellos.

Es como preguntar cómo las personas derivan como una solución para x = y . Ellos no! La ecuación no tiene una solución única.(x,y)=(0,0)x=y


En caso de que lo que quieras saber sea cómo se descubrió el primer teorema de punto fijo. Permítanme decir que también me pregunté cómo surgieron los teoremas de punto fijo / recursividad cuando los vi por primera vez. Parece muy ingenioso. Particularmente en la forma de la teoría de la computabilidad. A diferencia de lo que dice Yuval, no es el caso que la gente jugara hasta encontrar algo. Esto es lo que he encontrado:

Hasta donde recuerdo, el teorema se debe originalmente a SC Kleene. A Kleene se le ocurrió el teorema original de punto fijo al rescatar la prueba de inconsistencia del cálculo lambda original de Church. El cálculo lambda original de Church sufrió una paradoja tipo Russel. El cálculo lambda modificado evitó el problema. Kleene estudió la prueba de inconsistencia probablemente para ver cómo si el cálculo lambda modificado sufriría un problema similar y convirtió la prueba de inconsistencia en un teorema útil del cálculo lambda modificado. A través de su trabajo sobre la equivalencia del cálculo lambada con otros modelos de computación (máquinas de Turing, funciones recursivas, etc.) lo transfirió a otros modelos de computación.


¿Cómo derivar el operador que podría preguntar? Así es como lo tengo en cuenta. El teorema del punto fijo se trata de eliminar la autorreferencia.

Todos conocen la paradoja del mentiroso:

Soy una guarida

O en la forma más lingüística:

Esta oración es falsa.

Ahora, la mayoría de las personas piensan que el problema con esta oración es con la autorreferencia. ¡No lo es! La autorreferencia puede eliminarse (el problema es con la verdad, un lenguaje no puede hablar sobre la verdad de sus propias oraciones en general, ver el teorema de la indefinibilidad de la verdad de Tarski ). La forma en que se elimina la autorreferencia es la siguiente:

Si escribe la siguiente cita dos veces, la segunda vez entre comillas, la oración resultante es falsa: "Si escribe la siguiente cita dos veces, la segunda vez entre comillas, la oración resultante es falsa:"

λ

MMMxxx

Mx=f(xx)

Mλx.f(xx)

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

fλfY

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

Y

Kaveh
fuente
3

Por lo tanto, debe definir un combinador de punto fijo

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

pero sin recursividad explícita. Comencemos con el combinador irreducible más simple.

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

El xen el primer lambda se sustituye repetidamente por el segundo lambda. La conversión alfa simple aclara este proceso:

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)

Es decir, la variable en la primera lambda siempre desaparece. Entonces, si agregamos una fa la primera lambda

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

la fvoluntad sube

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

Tenemos nuestra omegaespalda. Ahora debería quedar claro que si agregamos un fa la segunda lambda, entonces faparecerá en la primera lambda y luego se disparará:

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

Ya que

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

podemos reescribir la expresión como

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

que es solo

f (Y f)

y tenemos nuestra ecuación Y f = f (Y f). Entonces el Ycombinador es esencialmente

  1. duplicar el f
  2. hacer el primer fmovimiento
  3. repetir
usuario3237465
fuente
2

Es posible que haya visto el ejemplo clásico de una ecuación sin una forma normal:

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

Se sugiere una ecuación similar para la recursividad general:

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

Yf=f(Yf)fR

Yf=(λx.f(xx))(λx.f(xx))
Y=λf.(λx.f(xx))(λx.f(xx))
DanielV
fuente