programación funcional con scheme
DESCRIPTION
Introducción a la programación funcional usando Scheme, un dialecto de LispTRANSCRIPT
Programación Funcionalcon Scheme
Por: Óscar López, [email protected]
OALP-2005 All Rights Reserved
Programación Funcional
• Un paradigma de programación, donde toda computación es resultado de evaluar funciones matemáticas
• Enfatiza la evaluación de expresiones, no la ejecución de instrucciones
• Las funciones son objetos de primer nivel
OALP-2005 All Rights Reserved
Ventajas y Características
• No hay operador de asignación• Una vez se fija el valor de una variable, no
se puede cambiar• No hay efectos secundarios• Transparencia referencial• Ideal para programación concurrente• No hay bucles• Facilita formalización y verificación
matemática
OALP-2005 All Rights Reserved
Cálculo-λ
• Modelo matemático formal de computación
• Ideado por Alonzo Church y Stephen Kleene en la década de 1930
• Define las funciones computables• Equivalente a la Máquina de Turing• Es el lenguaje de programación universal
más pequeño
OALP-2005 All Rights Reserved
Cálculo-λ: Definición Formal
• Definimos un conjunto infinito enumerable de identificadores {a, b, ..., y, z, x1, x2, ...}
• El conjunto de todas las expresiones lambda puede ser descrito por:1. <expr> ::= <identificador>2. <expr> ::= (λ <identificador> . <expr>) 3. <expr> ::= (<expr> <expr>)
OALP-2005 All Rights Reserved
Cálculo-λ: Definición Formal• La ligadura de ocurrencias de variables está definida por
las siguientes reglas:1. En una expresión de la forma V, donde V es una
variable, esta V es la única ocurrencia libre2. En una expresión de la forma λ V. E las ocurrencias
libres son las ocurrencias libres en E, exceptuando aquellas que estén en V. En este caso se dice que las ocurrencias de V en E están ligadas por el λ antes de V
3. En una expresión de la forma (E E') las ocurrencias libres son las ocurrencias libres en E y E'
• Se definen las siguientes transformaciones sobre expresiones lambda: conversión-α, reducción-β, conversión-η
OALP-2005 All Rights Reserved
Evolución de LISP y SchemeLISP
(1958)
Scheme(1974)
Common LISP(1984)
Common LISPANSI X3.226
(1994)Scheme R6RS
(2006)
CLOS
OALP-2005 All Rights Reserved
Características de Scheme• Estándar minimalista• Variables con alcance léxico• Recursión de cola es mandatoria• Sistema de macros higiénicos• Promueve un estilo de programación funcional• Los programas son datos y los datos son
programas• Continuaciones explícitas• Tipos dinámicos• Recolector de basura• Compilación nativa o máquina virtual
OALP-2005 All Rights Reserved
Entorno de Programación
• Un “mundo” que siempre está en el REPL• Lectura: chequea la
sintaxis de una expresión
• Evaluación: ejecuta la expresión
• Impresión: muestra el resultado de la ejecución
• El REPL se ejecuta en el contexto de un entorno global; puede visualizarse como un diccionario que asocia nombres a valores
OALP-2005 All Rights Reserved
Tipos de DatosTipo Ejemplos
booleano #t #f
entero 1 -2 3 42
racional 1/4 36/8
real 3.1416 1.2e+4
complejo 0+i 2+3i
carácter #\c #\space #\tab #\newline
símbolo 'var 'xyz
cadena "¡Hola, Mundo!"
lista '(1 2 3 4 5)
vector #(1 2 3 4 5)
estructura (define-struct persona (nombre cc dir tel))
OALP-2005 All Rights Reserved
Expresiones-S• Son una convención para representar datos o
expresiones en un programa• Se construyen usando notación prefija (polaca,
funcional) y paréntesis• Pueden estar arbitrariamente anidadas• Están conformadas por átomos y pares (celdas) cons• Cuando una expresión-s denota la aplicación de un
procedimiento, se evalúa en orden aplicativo:1. Se evalúan todas las sub-expresiones2. Se aplica el procedimiento resultado de evaluar la
sub-expresión que está más a la izquierda (el operador) a los argumentos, que son los valores de las demás sub-expresiones (los operandos)
OALP-2005 All Rights Reserved
Expresiones-S: Ejemplos
(+ 1 1)
(/ (+ (sqr 3) 1)
(* 3 4 5))
(or (>= 7 5)
(not (< 3 8)))
((if (zero? 0) + *) 7 5)
OALP-2005 All Rights Reserved
ConvencionesConvención Ejemplos
nulo '()
comentarios ;
cualquier valor distinto de #fes verdadero
#t
(if (and 0 '()) "mal uso")
nombres en minúsculas separados por guiones
(make-vector 5)
(make-hash-table 'equal)
conversiones (number->string 10)
predicados (null? '(1 2 3))
operaciones destructivas (asignación)
(define x 0)
(set! x 1)
comparaciones (char>=? #\z #\a)
OALP-2005 All Rights Reserved
Formas Especiales;; también case
(cond ((bool-exp1) eval-exp1)
...
((bool-expn) eval-expn)
(else eval-exp))
;; también let* y letrec
(let ((var1 exp1)
...
(varn expn))
use-var1-...-varn)
(and bool-exp1
...
bool-expn)
(or bool-exp1
...
bool-expn)
;; también when
;; y unless
(if (bool-exp)
then-exp
else-exp)
OALP-2005 All Rights Reserved
Formas Especiales: Ejemplos(let ((x 2)
(y 3))
(* x y))
(let* ((x 2)
(y (+ x 1)))
(* x y))
(letrec ((y x)
(x 5))
x)
(and #t #f (/ 1 0))
(or #f #t (/ 1 0))
(if (= 1 1)
"then-exp"
(/ 1 0))
(define a 1)
(cond ((= a 1) "uno")
((= a 2) "dos")
(else "else"))
OALP-2005 All Rights Reserved
Definiciones• Scheme usa la siguiente construcción para asociarle un
nombre a un valor:(define <nombre-nuevo> <valor-inicial>)
• Las parejas nombre/valor son almacenadas y buscadas en el diccionario que constituye el entorno global de ejecución
• Es posible asociar un nombre a: valores constantes, el resultado de evaluar otras expresiones, procedimientos, etc.
• Cuando se define un nuevo procedimiento, éste tendrásu propio entorno local de ejecución
• Las definiciones se pueden anidar (estructura de bloque)
OALP-2005 All Rights Reserved
Definiciones: Ejemplos(define x 7)
(define y (* x x))
(define suma +)
(define (pitagoras x y)(sqrt (+ (sqr x) (sqr y))))
(define (es-par n)(define (par?)(if (= (modulo n 2) 0) #t #f))
(if (par?)(print "es par")(print "es impar")))
OALP-2005 All Rights Reserved
Procesos Recursivos Lineales(define (factorial n)
(if (= n 1)
1
(* n (factorial (- n 1)))))
OALP-2005 All Rights Reserved
Procesos Recursivos Arbóreos(define (fib n)
(cond ((zero? n) 0)
((= n 1) 1)
(else (+ (fib (- n 1))
(fib (- n 2))))))
OALP-2005 All Rights Reserved
Procesos Iterativos
(define (factorial n)(fact-iter 1 1 n))
(define (fact-iter producto contador n)(if (> contador n)
producto(fact-iter (* contador producto)
(+ contador 1) n)))
OALP-2005 All Rights Reserved
Expresiones Lambda• Similares a sus contrapartes en el cálculo-λ, son
funciones anónimas de la forma:(lambda (<parámetros-formales>) <cuerpo>)
• Sin embargo, las expresiones lambda de Schemeson formas especiales que pueden recibir más de un parámetro
• Al evaluarlas, retornan un procedimiento• El entorno en el que la expresión lambda fue
evaluada es recordado como parte del procedimiento retornado
• La definición de una función y la asignación de un nombre a ésta no siempre ocurren de manera simultánea
OALP-2005 All Rights Reserved
Expresiones Lambda: Ejemplos(lambda (x) (* x x))
((lambda (x) (* x x)) 8)
(define cuadrado(lambda (x) (* x x)))
(cuadrado 8)
(define (cuadrado x)(* x x))
(cuadrado 8)
(let ((x 1))(define f (lambda (y) (+ x y)))(let ((x 2))
(f 3)))
OALP-2005 All Rights Reserved
Currying
• Técnica que permite transformar una función que recibe múltiples argumentos en una secuencia de funciones que reciben un solo argumento
• Nombrada en honor al lógico Haskell Curry• La clave está en recibir el primer argumento,
retornar una función que recibe el siguiente argumento y así sucesivamente
• En ocasiones puede ser útil disponer de las funciones “incompletas” que se obtienen cuando no se proporcionan todos los argumentos
OALP-2005 All Rights Reserved
Currying: Ejemplos(define (pitagoras? a b c)(= (sqr a) (+ (sqr b) (sqr c))))
(pitagoras? 5 3 4)
(define pitagoras?(lambda (a)
(lambda (b)(lambda (c)
(= (sqr a) (+ (sqr b) (sqr c)))))))(((pitagoras? 5) 3) 4)
(define por-n(lambda (factor)
(lambda (numero)(* factor numero))))
(define por-2 (por-n 2))(por-2 192)
(define por-23 (por-n 23))(por-23 86)
OALP-2005 All Rights Reserved
Combinador-Y• Conocido como un “combinador de punto fijo” en términos
matemáticos; es una función que computa puntos fijos de otras funciones
• Un punto fijo es un valor que permanece “fijo” después de aplicar una función. Formalmente: x es un punto fijo de una función f si f(x) = x
• En algunas formalizaciones matemáticas, como el cálculo-λ, todas las funciones tienen un punto fijo
• Haskell Curry descubrió la función Y del cálculo-λ, que computa un punto fijo para cualquier función que se le proporcione
• Formalmente: Y = λf.(λx.(f (x x)) λx.(f (x x))) . Cumple con la propiedad: ∀f f(Y(f)) = Y(f)
• Utilidad práctica: ¡permite definir funciones recursivas anónimas!
OALP-2005 All Rights Reserved
Combinador-Y: Ejemplos(define (Y X)((lambda (proc)
(proc proc))(lambda (proc)(X (lambda (arg)
((proc proc) arg))))))
(define factorial(Y (lambda (fact)
(lambda (n)(if (= n 1)
1(* n (fact (- n 1))))))))
(factorial 5)
OALP-2005 All Rights Reserved
Listas
• Recordar: LISP significa List Processor• Las listas son la estructura de datos más
importante en Scheme, pero no son fundamentales
• En cambio, los pares (celdas) cons si son fundamentales
• Los procedimientos primitivos usados para manipular pares son:• cons : recibe dos argumentos y retorna un par• car : retorna el primer componente de un par• cdr : retorna el segundo componente de un par
OALP-2005 All Rights Reserved
Listas
• Las listas se construyen a partir de sucesivas aplicaciones de cons, donde el primer elemento es un valor y el segundo un par o nulo
(cons 1 (cons 2 (cons 3 (cons 4 (cons 5 '())))))
• Alternativamente, también se pueden crear listas usando las siguientes formas especiales:
(list 1 2 3 4 5)
'(1 2 3 4 5)
OALP-2005 All Rights Reserved
Listas: Ejemplos
(car '(1 2 3 4 5))1
(cadr '(1 2 3 4 5))2
(cons 1 (cons 2 (cons 3 (cons 4 (cons 5
'())))))
(cdr '(1 2 3 4 5)) (cdar'((1 2) (3 4) (5 6)))
(caaddr'((1 2) (3 4) (5 6)))
5
OALP-2005 All Rights Reserved
Funciones de Orden Superior• Reciben una función como argumento o retornan
una función como resultado• Un concepto originado en las matemáticas. Por
ejemplo, las derivadas e integrales son funciones de orden superior
• Ejemplos de uso:• Una función que requiere otra función como
parámetro es una plantilla, donde la función recibida modifica su comportamiento
• Si las funciones son cerraduras, pueden emplearse para definir estructuras de control
• Útiles para construir iteradores y enumeradores sobre estructuras de datos
OALP-2005 All Rights Reserved
Funciones de Orden Superior: Ejemplos
(define (f x) (sqr x))
(define (g x) (+ x 1))
(define h1 (compose f g))
(define h2 (compose g f))
(h1 5)
(h2 5)
(map + '(1 2 3) '(4 5 6))
(filter (lambda (x) (> x 5)) '(0 2 4 6 8 10))
(mergesort '(-1 7 10 0 2 2 -3)
(lambda (x y) (>= x y)))
OALP-2005 All Rights Reserved
Evaluación Perezosa• Una expresión no se evalúa de inmediato, la evaluación se
pospone hasta el momento en que sea necesaria• Scheme permite usar evaluación estricta o perezosa, pero
esta última debe programarse de manera explícita:• (delay <expresión>) retorna una promesa, que puede
ser evaluada más adelante• (force <promesa>) evalúa una promesa y retorna el
valor resultante• El valor de una promesa es recordado, de tal forma que si
force es llamado nuevamente, se retorna el valor previamente computado
• Útil para trabajar con estructuras de datos infinitas• Permite “pegar” programas de una forma completamente
distinta
OALP-2005 All Rights Reserved
Evaluación Perezosa: Ejemplos
(let ((promesa (delay (+ 1 2))))(list (force promesa) (force promesa)))
(define (next n)(cons n (delay (next (+ n 1)))))
(define a-stream (next 0))
(define head car)(define (tail stream)
(force (cdr stream)))
(head (tail (tail a-stream)))
OALP-2005 All Rights Reserved
Bibliografía1. Theo D’Hondt y Wolfgang De Meuter. “Scheme in 2 days”.
Vrije Universiteit Brussel2. Harold Abelson, Gerald Sussman y Julie Sussman.
“Structure and Interpretation of Computer Programs”. MIT Press
3. John Hughes. “Why Functional Programming Matters”. Institutionen för Datavetenskap, Chalmers Tekniska Högskola
4. Combinador-Y. http://www.ece.uc.edu/~franco/C511/html/Scheme/ycomb.html
5. Teach Yourself Scheme in Fixnum Days. http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme.html
6. Wikipedia. http://en.wikipedia.org/wiki/Main_Page