Cálculo Lambda (Cálculo-λ), originalmente creado por Alonzo Church, es el lenguaje de programación más pequeño del mundo. A pesar de no tener números, cadenas, valores booleanos o cualquier tipo de datos no funcional, el cálculo lambda se puede utilizar para representar cualquier máquina de Turing.
El cálculo lambda se compone de 3 elementos: variables, funciones y aplicaciones.
| Nombre | Sintaxis | Ejemplo | Explicación |
|---|---|---|---|
| Variable | <nombre> |
x |
una variable llamada "x" |
| Función | λ<parámetro>.<cuerpo> |
λx.x |
una función con parámetro "x" y cuerpo "x" |
| Aplicación | <función><variable o función> |
(λx.x)a |
llamando a la función "λx.x" con el argumento "a" |
La función más básica es la función de identidad: λx.x que es equivalente a
f(x) = x. La primera "x" es el argumento de la función y la segunda es el
cuerpo de la función.
λx.x, "x" se llama una variable enlazada porque está tanto en
el cuerpo de la función como en el parámetro.λx.y, "y" se llama variable libre porque nunca se declara de antemano.Evaluación se realiza a través de β-Reduction, que es, esencialmente, sustitución de ámbito léxico.
Al evaluar la expresión (λx.x)a, reemplazamos todas las ocurrencias de "x"
en el cuerpo de la función con "a".
(λx.x)a evalúa a: a(λx.y)a evalúa a: yIncluso puedes crear funciones de orden superior:
(λx.(λy.x))a evalúa a: λy.aAunque el cálculo lambda tradicionalmente solo admite funciones de un solo parámetro, podemos crear funciones multiparamétricas usando una técnica llamada Currificación.
(λx.λy.λz.xyz) es equivalente a f(x, y, z) = ((x y) z)Algunas veces λxy.<cuerpo> es usado indistintamente con: λx.λy.<cuerpo>
Es importante reconocer que el cálculo lambda tradicional no tiene números, caracteres ni ningún tipo de datos que no sea de función.
No hay "Verdadero" o "Falso" en el cálculo lambda. Ni siquiera hay un 1 o un 0.
En vez:
T es representado por: λx.λy.x
F es representado por: λx.λy.y
Primero, podemos definir una función "if" λbtf que devuelve
t si b es Verdadero y f si b es Falso
IF es equivalente a: λb.λt.λf.b t f
Usando IF podemos definir los operadores lógicos booleanos básicos:
a AND b es equivalente a: λab.IF a b F
a OR b es equivalente a: λab.IF a T b
a NOT b es equivalente a: λa.IF a F T
Note: IF a b c es esencialmente diciendo: IF((a b) c)
Aunque no hay números en el cálculo lambda, podemos codificar números usando Númeral de Church.
Para cualquier número n: n = λf.f n así:
0 = λf.λx.x
1 = λf.λx.f x
2 = λf.λx.f(f x)
3 = λf.λx.f(f(f x))
Para incrementar un númeral de Church, usamos la función sucesora
S(n) = n + 1 que es:
S = λn.λf.λx.f((n f) x)
Usando el sucesor, podemos definir AGREGAR:
AGREGAR = λab.(a S)n
Desafío: intenta definir tu propia función de multiplicación!
Sean S, K, I las siguientes funciones:
I x = x
K x y = x
S x y z = x z (y z)
Podemos convertir una expresión en el cálculo lambda en una expresión en el cálculo del combinador de SKI:
λx.x = Iλx.c = Kcλx.(y z) = S (λx.y) (λx.z)Tome el número 2 de Church por ejemplo:
2 = λf.λx.f(f x)
Para la parte interior λx.f(f x):
λx.f(f x)
= S (λx.f) (λx.(f x)) (case 3)
= S (K f) (S (λx.f) (λx.x)) (case 2, 3)
= S (K f) (S (K f) I) (case 2, 1)
Así que:
2
= λf.λx.f(f x)
= λf.(S (K f) (S (K f) I))
= λf.((S (K f)) (S (K f) I))
= S (λf.(S (K f))) (λf.(S (K f) I)) (case 3)
Para el primer argumento λf.(S (K f)):
λf.(S (K f))
= S (λf.S) (λf.(K f)) (case 3)
= S (K S) (S (λf.K) (λf.f)) (case 2, 3)
= S (K S) (S (K K) I) (case 2, 3)
Para el segundo argumento λf.(S (K f) I):
λf.(S (K f) I)
= λf.((S (K f)) I)
= S (λf.(S (K f))) (λf.I) (case 3)
= S (S (λf.S) (λf.(K f))) (K I) (case 2, 3)
= S (S (K S) (S (λf.K) (λf.f))) (K I) (case 1, 3)
= S (S (K S) (S (K K) I)) (K I) (case 1, 2)
Uniéndolos:
2
= S (λf.(S (K f))) (λf.(S (K f) I))
= S (S (K S) (S (K K) I)) (S (S (K S) (S (K K) I)) (K I))
Al expandir esto, terminaríamos con la misma expresión para el número 2 de Church nuevamente.
El cálculo del combinador SKI puede reducirse aún más. Podemos eliminar
el combinador I observando que I = SKK. Podemos sustituir
todos los 'I' con SKK.
El cálculo del combinador SK todavía no se encuentra en su expresión mínima. Definiendo:
ι = λf.((f S) K)
Tenemos que:
I = ιι
K = ι(ιI) = ι(ι(ιι))
S = ι(K) = ι(ι(ι(ιι)))
¿Tienes una sugerencia o rectificación? Abre un issue en el repositorio de GitHub, o haz un pull request tu mismo
Originalmente contribuido por Max Sun, y actualizado por 2 colaboradores.