Las expresiones o términos lambda, se escriben utilizando 3 elementos básicos.
3 elementos: variables, funciones, y aplicaciones.
| Nombre | Sintaxis | Ejemplo | Explicación |
|---|---|---|---|
| Variable | <nombre> |
x |
una variable llamada “x” |
| Función | λ<parámetro>.<término> |
λx.x |
una función con parámetro “x” y cuerpo “x” |
| Aplicación | <término><término> |
(λx.x)a |
llamar la función “λx.x” con el parámetro “a” |
La función más simple es la identidad: λx.x que es equivalente a f(x) = x.
Ejemplos:
x
xy
xzyx
(xz)(yx)
λx.x
(λx.x)y
(λz.(λx.y))
(x(λz.z))z
Parece que el cálculo lambda solo soporta funciones con un solo parámetro, pero podemos crear funciones que toman 2 parámetros o más con una técnica llamada currificación.
(λx.λy.λz.xyz) equivale a f(x, y, z) = ((x y) z)A menudo se escribe directamente λxy.<cuerpo> en lugar de: λx.λy.<cuerpo>
¿Qué significa el término xyz? ¿Es (xy)z o x(yz)?
Respuesta : (xy)z
La aplicación es asociativa hacia la izquierda.
λx.x, “x” es una variable ligada porque está al mismo tiempo en el cuerpo de la función y es parámetro de ella.λx.y, “y” es una variable libre porque no fue declarada en esa función.Un término lambda se evalua con una regla llamada β-reducción, que es básicamente sustitución sintáctica.
Cuando se evalua la expresión (λx.x)a, se reemplazan todas las ocurrencias ligadas de “x” en el cuerpo de la función por “a”.
(λx.x)a se vuelve: a(λx.y)a se vuelve: yIncluso se puede crear funciones que devuelven funciones:
(λx.(λy.x))a se vuelve: λy.a(λx.(x + ((λx.x+1)3)))2
Tenemos dos abstracciones anidadas que usan la misma variable como parámetro formal, “x”. Si reemplazamos todas las “x” por 2, cambiamos el sentido de la abstracción interna:
2 + ((λx.2+1)3))
Solución al problema 1: cuando queremos reducir (λx.M)N, debemos solo reemplazar las ocurrencias libres en M por N.
((λx.λy.x)y)z
Cuando está aplicada a 2 parámetros, la expresión λx.λy.x debería devolver el primero, entonces la expresión anterior debería devolver y.
Pero si hacemos un reemplazo “ingenuo”:
((λx.λy.x)y)z
(λy.y)z <- `y` se convierte en variable ligada - cambia el significado de la abstacción
z
Solución: α-conversión = renombrar parametros formales para conservar el significado de las abstracciones, antes de proceder a la reducción:
((λx.λy.x)y)z
((λx.λu.x)y)z <- α-conversión
(λu.y)z
y
El nombre es un poco engañoso porque indica que “reducir” un término lo achica. En realidad, puede reducir, aumentar o dejar igual el tamaño de un término lambda.
Unos ejemplos:
(λx.xx)(λx.xx)
(λx.xx)(λx.xx)
(λx.xxx)(λx.xxx)
(λx.xxx)(λx.xxx)(λx.xxx)
(λx.xxx)(λx.xxx)(λx.xxx)(λx.xxx)
(λx.xx)(λa.λb.bbb)
(λa.λb.bbb)(λa.λb.bbb)
λb.bbb
Un término lambda está en forma normal si no se puede aplicarle más beta-reducción.
Un término lambda tiene forma normal si, aplicándole alguna secuencia de beta-reducciones, se puede convertir en un término en forma normal.
(λz.zz)(λz.zz) que es un “bucle infinito”.(λx.λy.y)((λz.zz)(λz.zz))Para hacer una reducción “normal”, siempre elegir, entre las aplicaciones posibles, las que están más “afuera”, y entre ellas, las que están más a la izquierda.
En programación, la reducción normal es parecida al estilo “call-by-name” para llamar funciones, donde se evalua el parametro real recién cuando el parametro formal se necesita.
Si el parametro formal no se usa, entonces se ahorra el trabajo de evaluar el parametro real.
Seguramente están acostumbrados a lenguajes con “call by value”, como C:
Este programa siempre va a ejecutar contar_palabras_de_wikipedia() por más que no se use el resultado.
Si C fuera un lenguaje “call by name” no lo haría.
La aplicación más afuera y más a la izquierda no puede ser parte de otra aplicación.
Por lo cual, reducirla equivale a ejecutar el cuerpo de la función, en lugar de evaluar su parametro actual.
Si esa función ignora su parámetro, entonces esa reducción puede “hacer desaparecer” otras aplicaciones.
Por esa razón intuitiva, la reducción normal nos lleva a la forma normal si existe, por más que otras secuencias de reducciones no lo harían.
(λy.y(λx.x)z)(λy.x(λx.x)z)(λy.y(λy.y)yx)(λy.y(λx.x)z)(λy.x(λx.x)z)(λxyz.x(λy.yz)w), (λtuv.t(λz.zv))w(λxyz.x(λy.yz)w), (λxyw.x(λy.yw)z)(λxyz.x(λy.yz)w), (λxtz.x(λu.tz))w(λxyz.x(λy.yz)w)(λx.xy), (λxyw.x(λy.yz)w)(λz.zy)(λx.λy.xy)(λy.yz)(λx.λy.xy)(λz.yz)z(λx.(λy.x)yλz.z)(λy.yz)(λf.(λx.f(xx))(λx.f(xx)))(λn.λm.n(λn.λxy.nx(xy))m)(λxy.xxy)(λxy.xy)