Está en la página 1de 5

Part I

Programación Funcional con el


Cálculo Lambda
1 Revisión
El cálculo λ es un cálculo de funciones con una sintaxis simple:
e ::= x (V ariables)
| λx.e (Abstracción)
| e1 e2 (Aplicación)
Existen varias estrategias de evaluación basadas en la reducción β :
(λx.e) e0 →β [e0 /x]e
¿Cómo usar este cálculo simple en lenguajes de programación reales?

2 Programación Funcional
El cálculo lambda es un lenguaje funcional prototı́pico con:

• ausencia de efectos colaterales

• varias estrategias de evaluación


• aplicación de funciones únicamente (el cálculo lambda puro no tiene otros
tipos de datos)

Para diseñar un lenguaje de programación debemos saber:

• ¿Cómo programar con funciones?

• ¿Cómo programar solo con funciones?

3 Programación con Funciones


La programación funcional posee un estilo que se basa en la aplicación de nu-
merosas funciones.
Un paradigma funcional tı́pico usa funciones como argumentos o resultados
de otras funciones.
La programación funcional hace posible la programación orden superior.
Algunos lenguajes funciones impuros, como Lisp, ML, usan efectos laterales.
Algunos lenguajes definen caracterı́sticas avanzadas como entrada/salida,
referencias (apuntadores), arreglos, excepciones usando un estilo puramente fun-
cional.

1
4 Variables en Lenguajes Funcionales
La construcción let permite introducir nuevas variables
let x = e1 in e2
Esta construcción es similar a (λx.e2 )e1
La variable x es vinculada estáticamente a e1 por let en el ámbito de e2 .
Las variables son nombres de expresiones (p. ej., x es un nombre para el
valor denotado por e1 en e2 ).
La interpretación de variables como nombres de expresiones captura el sig-
nificado de let en matemáticas.
Las variables nunca se actualizan en un lenguaje funcional puro.

5 Transparencia Referencial
En programas funcionales puros, es posible razonar ecuacionalmente por sub-
stitución de iguales por iguales:
let x = e1 in e2 equivale a [e1 /x]e2
En un lenguaje imperativo, un efecto lateral en e1 podrı́a invalidar la ecuación
anterior.
El comportamiento de una función pura en un lenguaje funcional puro de-
pende solamente de los parámetros dados.
Este comportamiento es similar al de una función en matemáticas.
Esto hace más fácil entender y razonar en programas funcionales.

6 Expresividad de Cálculo Lambda


El cálculo lambda es un sistema mı́nimo pero suficientemente expresivo para
representar:

• tipos de datos (enteros, booleanos, listas, árboles, etc.)


• condicionales

• recursión

Esto es suficiente para codificar máquinas de Turing.


Corolario. e =β e0 es indecidible.
Sin embargo, ¿cuál es la codificación apropiada para todas esas construc-
ciones usando solamente funciones?
La idea consiste en codificar el comportamiento de los valores pero no su
estructura.

2
7 Codificación de Booleanos en el Cálculo Lambda
Los booleanos sirven para tomar decisiones, regresando uno de dos posibles
resultados.
Para su codificación en el cálculo lambda, un booleano es una función tal
que dados dos argumentos selecciona uno de ellos.
true = λx.λy.x
false = λx.λy.y
not = λx.λy.x y
and = λb.λc.λx.λy.b (c x y) y
if E1 thenE2 elseE3 = E1 E2 E3
La codificación tanto de and como de if then else resultan en evaluación
corta.
Ejemplos.
and false e →∗β false
if true then u else v
= (λx.λy.x) u v
→β (λy.u) v
→β u

8 Codificación de Pares en el Cálculo Lambda


Los pares sirven para agrupar elementos y seleccionar uno de sus elementos.
Un par es una función que dado un booleano regresa, o bien el elemento
izquierdo o bien el elemento derecho.
mkpair x y = λb.b x y
fst p = p true
snd p = p false
Ejemplo.
fst (mkpair x y)
→β (mkpair x y) true
→β true x y
→β x

9 Codificación de Números Naturales en el Cálculo


Lambda
Los números naturales se codifican como una estructura lineal que se construye
por iteración.
Un número natural n0 es una función que aplica una función f un número
n de veces a un valor inicial s.

3
00 = λf.λx.x
10 = λf.λx.f x
20 = λf.λx.f (f x)
...
n0 = λf.λx.f n x
A ésta representación unaria de los números naturales se les llama numerales
de Church.

10 Computación con Números Naturales


succ n = λf.λs.f (n f s) succesor
add n1 n2 = n1 succ n2 adición
mul n1 n2 = n1 (add n2 ) 0 multiplicación
iszero n = n(λb.false) true igualdadconcero

11 Computación con Números Naturales (ii) Ejem-


plo
mul 2 2
→β 2 (add 2) 0
→β (add 2)((add 2) 0)
→β 2 succ (add 2 0)
→β 2 succ (2 succ 0)
→β succ (succ (succ (succ 0)))
→β succ (succ (succ (λf.λs.f (0 f s))))
→β succ (succ (succ (λf.λs.f s)))
→β succ (succ (λg.λy.g ((λf.λs.f s) g y)))
→β succ (succ (λg.λy.g (g y)))
→∗β λg.λy.g (g (g (g y)))
=4

12 Computación con Números Naturales (iii) Ejem-


plo
add 0
= (λn1 .λn2 .n1 succ n2 ) 0
→β λn2 .0 succ n2
= λn2 .(λf.λs.s) succ n2
→β λn2 .n2
= λx.x
Para realizar cómputo con funciones podemos expresar algunas optimiza-
ciones pero se requiere reducir bajo lambda.

4
13 Codificación de la Recursión
Dado un predicado P codifica la función f ind tal que f ind P n evalúa el número
más pequeño que es más grande que n pero que satisface P :

• Usando f ind es posible codificar recursión


• f ind satisface la ecuación
f ind p n = if p n then n else f ind p (succ n)

Definamos:
F = λf.λp.λn.(p n) n (f p (succ n))
Necesitamos encontrar un punto fijo para F
f ind = F f ind
o
f ind p n = F f ind p n

14 Combinador de Punto Fijo


Definamos Y = λF.(λy.F (y y))(λx.F (x x))
Este es el llamado combinador de punto fijo.
Verificar que Y F es un punto fijo de F
Y F →β (λy.F (y y))(λx.F (x x)) →β F (Y F )
entonces Y F →β F (Y F )
Dada cualquier función en el cálculo lambda es posible calcular su punto fijo.
Podemos definir find como el punto fijo de la función anterior.
La esencia de la recursión es la auto aplicación y y