tema 3: características de la programación funcional · 2016-04-25 · conceptos de la...

51
Tema 3: Características de la programación funcional Sesión 5: El paradigma funcional (1) martes 22 de febrero de 2011 Referencias • Capítulo 1.1.5 SICP: [[http://mitpress.mit.edu/sicp/full-text/book/book-Z- H-10.html#%_sec_1.1.5][The Substitution Model for Procedure Application]] • Capítulo 10 PLP: Functional Languages martes 22 de febrero de 2011

Upload: others

Post on 06-Feb-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Tema 3: Características de la programación funcional

Sesión 5: El paradigma funcional (1)

martes 22 de febrero de 2011

Referencias

• Capítulo 1.1.5 SICP: [[http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-10.html#%_sec_1.1.5][The Substitution Model for Procedure Application]]

• Capítulo 10 PLP: Functional Languages

martes 22 de febrero de 2011

Page 2: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Hoy veremos

• Historia del paradigma funcional

• Características del paradigma funcional puro

• Modelo de computación basado en sustitución

martes 22 de febrero de 2011

Orígenes históricos

• Raíces teóricas, antes de aparecer los ordenadores

• 1930s: Alan Turing, Alonzo Church, Stephen Kleene, Emil Post, etc.

• Turing: Máquina de Turing, programación imperativa

• Kleene y Post: métodos abstractos, sustituciones algebraicas

• Church: Cálculo lambda, programación funcional

• Modelo de cálculo lambda basado en la definición de funciones y la aplicación de estas funciones a argumentos

martes 22 de febrero de 2011

Page 3: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Conceptos de la programación funcional

• Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML...

• (1958, John MacCarthy). LISP es el primer lenguaje de alto nivel basado en el paradigma funcional

• LISP no es programación funcional pura, tienen algunas instrucciones imperativas que permiten estado local y efectos laterales

• LISP lenguaje revolucionario, introduce nuevos conceptos: funciones como objetos primitivos, funciones orden superior, polimorfismo, listas, recursión, símbolos, homogeneidad de datos y programas, bucle “read-eval-print”

En un sentido estricto, la programación funcional define un programa como una función matemática que convierte unas entradas en unas salidas, sin estado

interno ni efectos laterales

martes 22 de febrero de 2011

Características de la programación funcional

• Programación declarativa:

• no hay asignación ni cambio de estado

• no hay referencias: identificadores asociados a valores

• no hay efectos laterales

• Recursión

• Funciones como tipos de datos primitivos

martes 22 de febrero de 2011

Page 4: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Programación declarativa vs imperativa

• Programación imperativa: pasos de ejecución y estado de variables

• Ejemplo de estado local (no existe en programación declarativa):

int x = x + 1;int y = y + 3;

(define (cuadrado x) (* x x))

int function contador () { static int c = 0;

c++; return c;}

contador(): 1contador(): 2contador(): 3

martes 22 de febrero de 2011

Programación declarativa vs imperativa

• Programación declarativa: Dentro del ámbito de declaración de las variables x1 … xn todas las ocurrencias de una expresión e que contiene únicamente las variables x1 … xn tienen el mismo valor.

• Consecuencia: optimización. Si una expresión e aparece en varios lugares dentro de un mismo ámbito, sólo es necesario evaluarla una vez.

(define (f x) ...)(+ (f 2) (f 2))

(define (f x) ...)(define y (f 2))(+ y y)

Una función llamada con los mismos argumentos siempre devuelve el mismo resultado

martes 22 de febrero de 2011

Page 5: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Modelo de computación de sustitución

• Un modelo computacional es un formalismo (conjunto de reglas) que definen el funcionamiento de un programa.

• En los lenguajes funcionales basados en la evaluación de expresiones, el modelo computacional define cuál va a ser el resultado de evaluar una determinada expresión.

• El modelo de sustitución se basa en una versión simplificada de la regla de reducción del cálculo lambda.

martes 22 de febrero de 2011

Modelo de computación de sustitución

• Reglas para evaluar una expresión e de Scheme:

• Si e es un valor primitivo, devolver ese mismo valor.

• Si e es una variable, devolver su valor asociado.

• Si e es una expresión del tipo (f arg1 … argn), donde f el nombre de un procedimiento primitivo (+, -, …), evaluar arg1 … argn y aplicar el procedimiento al resultado.

• Si e es una expresión del tipo (f arg1 … argn), donde f es el nombre de un procedimiento compuesto (definido con un define), sustituir f por su cuerpo, reemplazando cada parámetro formal del procedimiento por el correspondiente argumento evaluado. Evaluar la expresión resultante.

martes 22 de febrero de 2011

Page 6: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

(define (double x) (+ x x))(define (square y) (* y y))(define (f z) (+ square (double z)) 1))

Ejemplo modelo de sustitución

• Evaluamos (f (+ 2 1)) con orden aplicativo

martes 22 de febrero de 2011

Orden normal vs orden aplicativo

• Orden aplicativo (Scheme): se evalúan primero los argumentos, luego se sustituye

• Orden normal: se realizan todas las sustituciones hasta que se tiene una larga expresión formada por expresiones primitivas; se evalúa entonces

• Evaluamos (f (+ 2 1)) con orden normal

En programación funcional el orden normal y el orden aplicativo siempre devolverán el mismo resultado

martes 22 de febrero de 2011

Page 7: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Orden normal vs orden aplicativo

• El orden importa si no tenemos programación funcional pura:

(define (zero x) (- x x))(zero (random 10))

martes 22 de febrero de 2011

Simulación en Scheme

(load "simply.scm")(load "order.scm")(def (doble x) (+ x x))(def (cuadrado x) (* x x))(def (f z) (+ (cuadrado (doble z)) 1))(applic (f (+ 2 1)))(normal (f (+ 2 1)))

martes 22 de febrero de 2011

Page 8: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Ejercicios

• Dada la función:

• Evaluar la expresión (double (* 3 4)) en orden aplicativo y en orden normal. ¿Cuál es más eficiente?

• Dada la función:

• Evaluar la expresión (switch -1 (+ 1 2) (+ 2 3) (+ 3 4)) en orden aplicativo y en orden normal. ¿Cuál es más eficiente?

(define (double x) (+ x x))

(define (switch x a b c) (cond ((< x 0) a) ((= x 0) b) ((> x 0) c))))

martes 22 de febrero de 2011

Page 9: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Tema 3: Características de la programación funcional

Sesión 6: El paradigma funcional (2)

miércoles 23 de febrero de 2011

Referencias

• Capítulo 1.1.5 SICP: [[http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-10.html#%_sec_1.1.5][The Substitution Model for Procedure Application]]

• Capítulo 10 PLP: Functional Languages

miércoles 23 de febrero de 2011

Page 10: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Hoy veremos

• Programación funcional en LISP (y Scheme)

miércoles 23 de febrero de 2011

Programación funcional en LISP (y Scheme)

• LISP (y Scheme) no es funcional puro: tiene características que van más allá de la programación declarativa/funcional

• Algunas características:

• Funciones como tipos de dato primitivos y funciones de orden superior

• Polimorfismo

• Símbolos y dualidad entre datos y programa

miércoles 23 de febrero de 2011

Page 11: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Funciones como tipos de datos primitivos

• Las funciones son tipos primitivos en los lenguajes funcionales

• Un tipo primitivo es aquel que:

• Puede ser asignado a una variable

• Puede ser pasado como argumento a una función

• Puede ser devuelto como resultado de una invocación a una función

• Puede ser parte de un tipo de dato mayor

miércoles 23 de febrero de 2011

Forma especial lambda

• La forma especial lambda es la forma de Scheme de construir funciones anónimas (sin nombre) en tiempo de ejecución

• Sintaxis:

(lambda <arg1> ... <argn>) <cuerpo>)

(lambda (x) (* x x))(lambda (x y) (+ x y))

proc

proc

Al evaluar lambda, se crea una función

sin nombre

miércoles 23 de febrero de 2011

Page 12: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Función anónima (creada con lambda)

• Puede ser invocada directamente:

• Es un tipo de dato primitivo, como cualquier otra función

((lambda (x) (* x x)) 3)

miércoles 23 de febrero de 2011

Funciones como tipos de dato primitivos: función asignada a variable

• Función creada con define:

• Función creada con lambda:

(define cubo (lambda (x) (* x x x)))

proc

cuadrado

(define (cuadrado x)(* x x)))

proc

cubo

miércoles 23 de febrero de 2011

Page 13: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Funciones como tipos de datos primitivos: función como argumento de otra función. Ejemplo 1

(define (aplica f x y) (f x y))

(aplica + 2 3)(aplica * 4 5)(aplica string-append "hola" "adios")(aplica (lambda (x y) (sqrt (+ (* x x) (* y y)))) 3 4)

miércoles 23 de febrero de 2011

Funciones como tipos de datos primitivos: función como argumento de otra función. Ejemplo 2

(define (aplica-2 f g x) (f (g x)))(define (suma-5 x) (+ x 5))(define (doble x) (+ x x))

(aplica-2 suma-5 doble 3)(aplica-2 (lambda (x) (* x 2)) (lambda (x) (+ x 10)) 5)

miércoles 23 de febrero de 2011

Page 14: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Funciones como tipos de datos primitivos: función como valor devuelto por otra función

(define (hacer-sumador-k k) (lambda (x) (+ x k)))

(define g (hacer-sumador-k 5))(g 10)

proc

hacer-sumador-k

proc

g

miércoles 23 de febrero de 2011

Funciones de orden superior

• Funciones de orden superior: Son funciones que reciben otras funciones como argumento o devuelven una función como resultado

• Ejemplo, función map:

• Otro ejemplo:

(map cuadrado ‘(1 2 3 4 5))(map * ‘(1 2 3) ‘(4 5 6))

map recibe como argumentos una función y tantas listas (de igual

longitud) como argumentos

tenga la función

(define (operar f base lista) (if (null? lista) base (f (car lista) (operar f base (cdr lista)))))

miércoles 23 de febrero de 2011

Page 15: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Las funciones pueden formar parte de estructuras de datos mayor

• Ejemplo: lista de funciones

• Ejemplo de utilización:

(define lista-funcs (list doble suma-5 cuadrado))

(define (aplica-funcs lista-funcs x) (if (null? (cdr lista-funcs)) ((car lista-funcs) x) ((car lista-funcs) (aplica-funcs (cdr lista-funcs) x))))

(aplica-funcs lista-funcs 10)

miércoles 23 de febrero de 2011

Dualidad entre datos y código

• Los programas en Scheme son expresiones entre paréntesis

• Una expresión entre paréntesis es una lista de símbolos

• Por tanto, los programas (sin evaluar) se pueden considerar como datos (listas) y viceversa y, por tanto, podemos construirlos, desconstruirlos, y manipularlos como las listas

• Ejemplo: utilizando quote y eval, vamos a sumar una lista de números

(define (suma-lista lista-nums) (eval (cons '+ lista-nums)))

miércoles 23 de febrero de 2011

Page 16: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Ejercicios

• ¿Qué hace el siguiente código en Scheme?

• ¿Cómo habría que invocar a la función anterior para que devuelva 20?

• Define una función g que podamos invocar así y devuelva 18:

• Define una función h que se invoque de la siguiente forma y devuelva 6:

(lambda (f x) (f x x)))

(g (lambda (x) (+ x x)) (lambda (y) (* y y)) 3)

((h (lambda (x) (+ x x))) 3)

miércoles 23 de febrero de 2011

Page 17: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Tema 3: Características de la programación funcional

Sesión 7: El paradigma funcional (3)

martes 1 de marzo de 2011

Referencias

• Capítulo 10 PLP: Functional Languages

martes 1 de marzo de 2011

Page 18: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Hoy veremos

• Características de la programación funcional en LISP/Scheme

martes 1 de marzo de 2011

Características de la programación funcional

• Evaluación sin efectos laterales: paradigma declarativo y modelo de sustitución

• Funciones como tipos de datos primitivos: forma especial lambda

• Ámbitos de variables: forma especial let

• Dualidad entre datos y programas: formas especiales eval y apply

• Listas como elemento fundamental de procesamiento

• Recursión

martes 1 de marzo de 2011

Page 19: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Ámbito global de variables

• En Scheme existe un ámbito global de las variables en el que se les da valor utilizando la forma especial define

(define a "hola")(define b (string-append "adios" a))(define cuadrado (lambda (x) (* x x)))

martes 1 de marzo de 2011

Ámbito local: forma especial let

• En Scheme se define la forma especial let que permite crear un ámbito local en el que da valor a variables.

• Sintaxis:

• Las variables var1, … varn toman los valores devueltos por las expresiones exp1, … expn y el cuerpo se evalúa con esos valores.

(let ((<var1> <exp-1>) ... (<varn> <exp-n>)) <cuerpo>)

(let ((x 2) (y 5)) (+ x y))

martes 1 de marzo de 2011

Page 20: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

let mejora la legibilidad de los programas

• El uso de let permite abstraer operaciones y dar un nombre a los resultados, aumentando la legibilidad de los programa

(define (distancia x1 y1 x2 y2) (let ((dx (- x2 x1)) (dy (- y2 y1))) (sqrt (+ (cuadrado dx) (cuadrado dy)))))

martes 1 de marzo de 2011

El ámbito de las variables definidas en el let es local

• Las variables definidas en el let sólo tienen valores en el ámbito de la forma especial

(define x 5)(let ((x 1) (y 2)) (+ x y))xy

martes 1 de marzo de 2011

Page 21: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

let permite usar variables definidas en un ámbito superior

• Desde el ámbito definido por el let se puede usar el ámbito superior. Por ejemplo, en el siguiente código se usa la variable z definida en el ámbito superior.

(define z 8)(let ((x 1) (y 2)) (+ x y z))

martes 1 de marzo de 2011

Las variables del let pueden asociarse con cualquier valor

• Un ejemplo en el que definimos funciones de ámbito local: area-triangulo y apotema:

(define (area-hexagono lado) (let ((area-triangulo (lambda (base altura) (/ (* base altura) 2))) (apotema (lambda (lado) (* (sqrt 3) (/ lado 2)))))) (* 6 (area-triangulo lado (apotema lado))))

martes 1 de marzo de 2011

Page 22: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Variables en las asignaciones del let

• Las expresiones del let se evalúan todas antes de asociar ningún valor con las variables.

• No se realiza una asignación secuencial:

(define x 1)(let ((w (+ x 3)) (z (+ w 2))) ;; Error (+ w z))

martes 1 de marzo de 2011

Semántica del let

• Evaluar todas las expresiones de la derecha de las variables y guardar sus valores en variables auxiliares locales.

• Definir un ámbito local en el que se ligan las variables del let con los valores de las variables auxiliares.

• Evaluar el cuerpo del let en el ámbito local

martes 1 de marzo de 2011

Page 23: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Es posible implementar let utilizando lambda

• La semántica anterior queda clara cuando comprobamos que let se puede definir en función de lambda. La expresión:

• Se puede implementar como:

(let ((<var1> <exp1>) ... (<varn> <expn>)) <cuerpo>)

((lambda (<var1> ... <varn>) <cuerpo>) <exp1> ... <expn>)

(define x 5)(let ((x (+ 2 3)) (y (+ x 3))) (+ x y))

((lambda (x y) (+ x y)) (+ 2 3) (+ x 3))

martes 1 de marzo de 2011

let* permite asignaciones secuenciales

• La forma especial let* permite una asignación secuencial de las variables y las expresiones:

• ¿Cómo se puede implementar con let?

(let* ((x (+ 1 2)) (y (+ x 3)) (z (+ y x))) (* x y z)

martes 1 de marzo de 2011

Page 24: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

let* permite asignaciones secuenciales

• La forma especial let* permite una asignación secuencial de las variables y las expresiones:

• ¿Cómo se puede implementar con let?

(let* ((x (+ 1 2)) (y (+ x 3)) (z (+ y x))) (* x y z)

(let ((x (+ 1 2))) (let ((y (+ x 3))) (let ((z (+ y x))) (* x y z))))

martes 1 de marzo de 2011

let* permite asignaciones secuenciales

• El primer let crea un ámbito local en el que se evalúa el segundo let, que a su vez crea otro ámbito local en el que se evalúa el tercer let. Se crean tres ámbitos locales anidados, y en el último se evalúa la expresión (* x y z).

(let ((x (+ 1 2))) (let ((y (+ x 3))) (let ((z (+ y x))) (* x y z))))

martes 1 de marzo de 2011

Page 25: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

El ámbito definido en el let puede sobrevivir

• Un ejemplo avanzado del funcionamiento del let, en el que creamos una función en el ámbito del let:

• Sucede lo siguiente:

(define h (let ((x 3)) (lambda (y) (+ x y))))

1. Se invoca al let y se crea un entorno local en el que x vale 32. En ese entorno se crea una función de un parámetro que usa la variable x3. Se devuelve la función y se asocia a h

martes 1 de marzo de 2011

El ámbito definido en el let puede sobrevivir

• ¿Qué pasa cuando se llama a h? ¿Y si modificamos el valor de x en el ámbito global?

• Funcionamiento: cuando se llama a la función, el intérprete restaura el entorno que estaba activo cuando la expresión lambda se evaluó. Y lo aumenta con las variables de los parámetros formales ligadas al valor del argumento. En este ámbito se evalúa el cuerpo de la función.

(define h (let ((x 3)) (lambda (y) (+ x y))))

(h 5)(define x 10)(h 5)

martes 1 de marzo de 2011

Page 26: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

El mismo efecto sin let

• En el ejemplo siguiente la llamada (make-sumador 3) produce exactamente el mismo efecto que el let anterior.

(define (make-sumador x) (lambda (y) (+ x y)))(define h (make-sumador 3))(define x 10)(h 5)

martes 1 de marzo de 2011

El ámbito definido en el let puede sobrevivir

• Importante:

• Seguimos estando en el paradigma de programación funcional declarativa en el que no hay efectos laterales.

• El modelo de sustitución no explica correctamente este comportamiento. Veremos más adelante el modelo de entornos que sí lo hace.

• Llamamos entorno (environment) a un conjunto de valores asociados a variables. Utilizamos las palabras ámbito y entorno como sinónimos.

martes 1 de marzo de 2011

Page 27: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Closure

• En muchos lenguajes de programación modernos existe el concepto de closure

• Se llama closure a una función creada en tiempo de ejecución junto con el entorno en el que ésta se ha creado

• Lo veremos en profundidad más adelante

martes 1 de marzo de 2011

Dualidad entre datos y programas

• Los programas en Scheme son expresiones entre paréntesis

• Una expresión es una lista de símbolos

• Esto permite tratar a los programas como datos y viceversa

• La forma especial eval evalúa una expresión

• Un ejemplo: supongamos que queremos sumar una lista de números

(define (suma-lista lista-nums) (eval (cons '+ lista-nums)))

martes 1 de marzo de 2011

Page 28: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Forma especial apply

• Permite llamar a una función con una lista de argumentos

• Sintaxis:

• Ejemplos:

(apply <func> <lista-args>)

(apply + '(1 2 3 4))(apply '+ '(1 2 3 4)) ; no funciona: '+ es un identificador(apply (lambda (x y) (* x y)) '(2 4))

martes 1 de marzo de 2011

Ejemplo de dualidad de datos y programa calculadora

• Este programa no es funcional: realiza pasos de ejecución para leer las expresiones introducidas por el usuario y para imprimir el resultado de su evaluación.

(define (calculadora) (display "Introduce parámetros entre paréntesis: ") (define params (read)) (display "Introduce cuerpo:") (define cuerpo (read)) (define func (eval (append '(lambda) (list params) (list cuerpo)))) (display "Introduce argumentos entre paréntesis: ") (define args (read)) (apply func args))

martes 1 de marzo de 2011

Page 29: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Ejemplo avanzado

(define (rep-loop) (display "mi-interprete> ") ; imprime un prompt (let ((expr (read))) ; lee una expresión (cond ((eq? expr 'adios) ; el usuario quiere parar? (display "saliendo del bucle read-eval-print") (newline)) (else ; en otro caso (write (eval expr)) ; evaluar e imprimir (newline) (rep-loop)))))

martes 1 de marzo de 2011

Page 30: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Tema 3: Características de la programación funcional

Sesión 8: El paradigma funcional (4)

jueves 3 de marzo de 2011

Referencias

• Capítulo 10 PLP: Functional Languages

• Capítulo 2.2 SICP, Abelson & Sussman

jueves 3 de marzo de 2011

Page 31: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Hoy veremos

• Características de la programación funcional en LISP/Scheme

jueves 3 de marzo de 2011

Características de la programación funcional

• Evaluación sin efectos laterales: paradigma declarativo y modelo de sustitución

• Funciones como tipos de datos primitivos: forma especial lambda

• Ámbitos de variables: forma especial let

• Dualidad entre datos y programas: formas especiales eval y apply

• Listas como elemento fundamental de procesamiento: parejas, cons, car y cdr

• Recursión

jueves 3 de marzo de 2011

Page 32: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Ejemplo de dualidad de datos y programa calculadora

• Este programa no es funcional: realiza pasos de ejecución para leer las expresiones introducidas por el usuario y para imprimir el resultado de su evaluación.

(define (calculadora) (display "Introduce parámetros entre paréntesis: ") (define params (read)) (display "Introduce cuerpo:") (define cuerpo (read)) (define func (eval (append '(lambda) (list params) (list cuerpo)))) (display "Introduce argumentos entre paréntesis: ") (define args (read)) (apply func args))

jueves 3 de marzo de 2011

Ejemplo de dualidad de datos y programa calculadora

• Es importante darse cuenta de que la expresión:

• devuelve una lista que es una expresión lambda correcta, cuya evaluación va a crear un procedimiento al que se llama después. Por ejemplo:

• Si hiciéramos (append '(lambda) params cuerpo) ¿qué obtendríamos?

(append '(lambda) (list params) (list cuerpo))

(define params '(x y))(define cuerpo '(+ x y))

jueves 3 de marzo de 2011

Page 33: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Ejemplo de dualidad de datos y programa calculadora

• Es importante darse cuenta de que la expresión:

• devuelve una lista que es una expresión lambda correcta, cuya evaluación va a crear un procedimiento al que se llama después. Por ejemplo:

• Si hiciéramos (append '(lambda) params cuerpo) obtendríamos una lista con 6 elementos:

• Necesitamos obtener la lista '(lambda (x y) (+ x y)), una lista de 3 elementos

(append '(lambda) (list params) (list cuerpo))

(define params '(x y))(define cuerpo '(+ x y))

(append '(lambda) params cuerpo)-> (lambda x y + x y)

jueves 3 de marzo de 2011

Datos compuestos en Scheme

• En Scheme es posible crear datos compuestos.

• La forma de hacerlo es definiendo una construcción muy simple y usando esa construcción simple para hacer cosas más complicadas.

• El tipo de dato compuesto más simple es la pareja: una entidad formada por dos elementos.

• Se utiliza la función cons para construirla.

(cons 1 2)(1 . 2)

jueves 3 de marzo de 2011

Page 34: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Diagramas caja y puntero

• Las parejas se representan mediante este tipo de figuras

(cons 1 2)(1 . 2)

jueves 3 de marzo de 2011

Funciones de acceso a una pareja

• Podemos obtener el elemento correspondiente a la parte izquierda con el operador car y su parte derecha con el operador cdr

• Definición declarativa: Las funciones cons, car y cdr quedan perfectamente definidas con las siguientes ecuaciones

(define c (cons 1 2))> (car c) 1> (cdr c) 2

(car (cons x y)) = x(cdr (cons x y)) = y

jueves 3 de marzo de 2011

Page 35: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Nota histórica

• ¿De dónde vienen los nombres car y cdr?

• Realmente los nombres eran CAR y CDR (en mayúsculas)

• La historia se remonta al año 1959, en los orígenes del LISP y tiene que ver con el nombre que se les daba a ciertos registros de la memoria del IBM 709.

• Explicación completa: http://www.iwriteiam.nl/HaCAR_CDR.html

jueves 3 de marzo de 2011

Las parejas pueden contener cualquier tipo de dato

> (define c (cons 'hola #f))> (car c)'hola> (cdr c)#f

jueves 3 de marzo de 2011

Page 36: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Las parejas pueden contener cualquier tipo de dato

> (define c (cons 'hola #f))> (car c)'hola> (cdr c)#f

(define p1 (cons (lambda (x) (+ x 3)) 5))

• ¿Cómo se podría llamar a la función de la parte izquierda de la pareja con la parte derecha como argumento?

jueves 3 de marzo de 2011

Las parejas pueden contener cualquier tipo de dato

> (define c (cons 'hola #f))> (car c)'hola> (cdr c)#f

(define p1 (cons (lambda (x) (+ x 3)) 5))

• ¿Cómo se podría llamar a la función de la parte izquierda de la pareja con la parte derecha como argumento?

((car p1) (cdr p1)) -> 8

jueves 3 de marzo de 2011

Page 37: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Seguimos en el paradigma funcional

• Seguimos en el paradigma funcional

• Una vez creada una pareja no es posible modificar sus contenidos.

• Aunque Scheme tiene primitivas para modificar el contenido de las parejas.

jueves 3 de marzo de 2011

Las parejas son un tipo de dato de primer orden

• Una pareja es también un tipo de datos de primer orden: puede pasarse como argumento y devolverse como resultado de una función.

> (define (doble-car pareja) (* 2 (car pareja)))> (doble-car (cons 4 2))8

> (define (doble-pareja pareja) (cons (doble-car pareja) (doble-cdr pareja)))> (doble-pareja (cons 2 3))(4 . 6)

jueves 3 de marzo de 2011

Page 38: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Propiedad de clausura: parejas de parejas

• Las parejas pueden formar parte de otras parejas.

• Esta última propiedad se denomina clausura de la operación cons.

• El resultado de un cons puede usarse para construir otras parejas.

• Ejemplo:

• Expresión equivalente:

(define p1 (cons 1 2))(define p2 (cons 3 4))(define p (cons p1 p2))

(define p (cons (cons 1 2) (cons 3 4)))

jueves 3 de marzo de 2011

Ejemplo

(define p (cons (cons 1 (cons 3 4)) 2))

• ¿Qué figura representa la estructura anterior?

jueves 3 de marzo de 2011

Page 39: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Funciones c????r

• Es equivalente a:

• El nombre de la función se obtiene concatenando a la letra "c", las letras "a" o "d" según hagamos un car o un cdr y terminando con la letra "r"

• Hay definidas 2^4 funciones de este tipo: caaaar, caaadr, …, cddddr.

> (car (cdr (car p)))3

> (cadar p)))3

jueves 3 de marzo de 2011

Función pair?

• La función pair? nos dice si un objeto es atómico o es una pareja

> (pair? 3)#f>(pair? (cons 3 4))#t>(not (pair? (cons 2 3)))#f

jueves 3 de marzo de 2011

Page 40: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Repaso de listas

(list 1 2 3 4)'(1 2 3 4)

(define hola 1)(define que 2)(define tal 3)

(list hola que tal)'(hola que tal)

(define a '(1 2 3))(car a)(cdr a)(length a)(length '())(append '(1) '(2 3 4) '(5 6 7) '())

jueves 3 de marzo de 2011

Construcción de listas con parejas

• Definición recursiva con parejas:

• Una pareja en la que el primer elemento es un dato y el segundo el resto de la lista.

• Un símbolo especial '() que denota la lista vacía

• Ejemplo:

(cons 1 (cons 2 (cons 3 '())))

jueves 3 de marzo de 2011

Page 41: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Lista vacía

• No es un símbolo

• No es una pareja

• Es una lista

> (symbol? '())#f> (pair? '())#f> (length '())0

jueves 3 de marzo de 2011

Funciones list? y null?

• Nos permite comprobar si un dato es una lista

• Para comprobar si una lista está vacía utilizamos la función null?

> (list? '(1 2 3))#t> (list? '())#t> (list? 2)#f

> (null? '())#t

jueves 3 de marzo de 2011

Page 42: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

car y cdr para recorrer listas

• Ahora se entiende mejor por qué las funciones que permiten recorrer una lista son car y cdr como en el siguiente ejemplo:

(define lista (cons 1 (cons 2 (cons 3 (cons 4 '())))))(car lista)(cdr lista)

jueves 3 de marzo de 2011

cons para formar una nueva lista

> (define l1 '(1 2 3 4))> (cons 'hola l1)(hola 1 2 3 4)

jueves 3 de marzo de 2011

Page 43: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Ejercicio resuelto

• Define el procedimiento (insertar-list lista l2 n) que reciba dos listas y un número n. Deberá insertar en el mismo nivel, la l2 en la lista en la posición indicada por n (suponemos que n nunca será mayor que la longitud de la lista):

> (define (insertar-list lista l2 n) (if (= n 0) (append l2 lista) (cons (car lista) (insertar-list (cdr lista) l2 (- n 1)))))> (insertar-list '(1 2 3 4) '(a b) 3)(1 2 3 a b 4)

jueves 3 de marzo de 2011

Ejercicios

• Dibuja el diagrama caja y puntero asociado a estas estructuras de datos:

• Dibuja el diagrama caja y puntero asociado a esta estructura de datos:

• Implementa la función mi-lis-ref que reciba un número n y una lista como argumento y devuelva el elemento n-ésimo de la lista (empezando a contar en 0).

• Implementa la función mi-list-tail que reciba un número n y una lista como argumento y devuelva la lista resultante de quitar n elementos de la lista original

((x) y z)(x (y z))((a) b (c ()))

(cons (cons 2 (cons 3 (cons 4 ‘()))) (cons 1 2))

jueves 3 de marzo de 2011

Page 44: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

list devuelve la primera pareja de la lista

• La construcción de una lista devuelve la primera pareja de la misma. Así, tras evaluar la expresión:

• La variable lista tomará el valor de la primera pareja de la lista, la pareja formada por un 1 y el resto de la lista. Es lo mismo que cuando hacemos:

• cons para formar una nueva lista

(define lista (list 1 2 3))

(define lista (cons 1 (cons 2 (cons 3 '()))))

> (define l1 '(1 2 3 4))> (cons 'hola l1)(hola 1 2 3 4)

martes 8 de marzo de 2011

Scheme muestra las estructuras compuestas como listas

• Cuando Scheme imprime una estructura compuesta por parejas, va recorriendo la estructura intentando escribirla como una lista. Por ejemplo:

• Esta última estructura no es una lista

> (cons 1 (cons 2 (cons 3 '())))(1 2 3)>(cons 1 (cons 2 3))(1 2 . 3)

martes 8 de marzo de 2011

Page 45: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Listas con elementos compuestos

• Las listas pueden contener cualquier tipo de elementos, incluyendo otras parejas.

• La siguiente estructura se denomina lista de asociación: una lista cuyos elementos son parejas:

• ¿Cuál sería el diagrama de la lista anterior?

• La expresión equivalente utilizando parejas:

(list (cons 'a 1) (cons 'b 2) (cons 'c 3)) -> ((a.1)(b.2)(c.2))

martes 8 de marzo de 2011

Listas con elementos compuestos

• Las listas pueden contener cualquier tipo de elementos, incluyendo otras parejas.

• La siguiente estructura se denomina lista de asociación: una lista cuyos elementos son parejas:

• ¿Cuál sería el diagrama de la lista anterior?

• La expresión equivalente utilizando parejas:

(list (cons 'a 1) (cons 'b 2) (cons 'c 3)) -> ((a.1)(b.2)(c.2))

(cons (cons 'a 1) (cons (cons 'b 2) (cons (cons 'c 3) '())))

martes 8 de marzo de 2011

Page 46: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Listas de listas

• Las listas, al igual que las parejas, pueden contener cualquier tipo de dato, incluso otras listas:

• La lista anterior también la podemos definir con quote:

• ¿Cuál sería su representación con parejas?

• ¿Y su diagrama caja y puntero?

(define l1 (list 1 2 3))(define l2 (list 1 l1 2 3))

(define l2 '(1 (1 2 3) 2 3))

martes 8 de marzo de 2011

Implementación de funciones sobre listas

• Implementa la función mi-append que reciba dos listas como argumento y devuelva una nueva lista compuesta por la concatenación de las dos listas recibidas.

martes 8 de marzo de 2011

Page 47: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Implementación de funciones sobre listas

• Implementa la función mi-append que reciba dos listas como argumento y devuelva una nueva lista compuesta por la concatenación de las dos listas recibidas.

(define (mi-append l1 l2) (if (null? l1) l2 (cons (car l1) (mi-append (cdr l1) l2))))

martes 8 de marzo de 2011

Implementación de funciones sobre listas

• Implementa la función mi-length que reciba una lista como argumento y devuelva el número de elementos que contiene (en el primer nivel).

> (mi-length '(1 2 3 (4 5 6)))4

martes 8 de marzo de 2011

Page 48: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Implementación de funciones sobre listas

• Implementa la función mi-length que reciba una lista como argumento y devuelva el número de elementos que contiene (en el primer nivel).

> (mi-length '(1 2 3 (4 5 6)))4

(define (mi-length items) (if (null? items) 0 (+ 1 (mi-length (cdr items)))))

martes 8 de marzo de 2011

Los datos compuestos pueden ser funciones

• Definimos la función mi-cons como:

• La función anterior es equivalente a la función cons de Scheme.

• Se devuelve un procedimiento que admite un argumento m (mensaje).

• Cuando al procedimiento se le pasa el mensaje 'car devolverá el argumento x original de mi-cons y cuando se le pasa el mensaje 'cdr devolverá el argumento y

(define (mi-cons x y) (lambda (m) (cond ((equal? m 'car) x) ((equal? m 'cdr) y) (else (error "mensaje no definido: " m)) )))

martes 8 de marzo de 2011

Page 49: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Los datos compuestos pueden ser funciones

• Definimos la función mi-cons como:

• ¿Cómo la utilizamos? Pensad en un ejemplo

(define (mi-cons x y) (lambda (m) (cond ((equal? m 'car) x) ((equal? m 'cdr) y) (else (error "mensaje no definido: " m)) )))

martes 8 de marzo de 2011

Los datos compuestos pueden ser funciones

• Definimos la función mi-cons como:

• ¿Cómo la utilizamos? Pensad en un ejemplo

(define (mi-cons x y) (lambda (m) (cond ((equal? m 'car) x) ((equal? m 'cdr) y) (else (error "mensaje no definido: " m)) )))

> (define p (mi-cons 'hola #f))> (p 'car)hola> (p 'cdr)#f

martes 8 de marzo de 2011

Page 50: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Los datos compuestos pueden ser funciones

• Definimos la función mi-cons como:

• Funciones

• Funciones que encapsulan la llamada a la función:

• Ahora no hay ninguna diferencia entre el comportamiento de las funciones originales y el de las nuestras

(define (mi-cons x y) (lambda (m) (cond ((equal? m 'car) x) ((equal? m 'cdr) y) (else (error "mensaje no definido: " m)) )))

martes 8 de marzo de 2011

Los datos compuestos pueden ser funciones

• Definimos la función mi-cons como:

• Funciones

• Funciones que encapsulan la llamada a la función:

• Ahora no hay ninguna diferencia entre el comportamiento de las funciones originales y el de las nuestras

(define (mi-cons x y) (lambda (m) (cond ((equal? m 'car) x) ((equal? m 'cdr) y) (else (error "mensaje no definido: " m)) )))

(define (mi-car pareja) (pareja 'car))

(define (mi-cdr pareja) (pareja 'cdr))

martes 8 de marzo de 2011

Page 51: Tema 3: Características de la programación funcional · 2016-04-25 · Conceptos de la programación funcional •Lenguajes funcionales puros: Miranda, Haskell, pH, Sisal, ML

Los datos compuestos pueden ser funciones

• Definimos la función mi-cons como:

• Funciones

• Funciones que encapsulan la llamada a la función:

• Ahora no hay ninguna diferencia entre el comportamiento de las funciones originales y el de las nuestras

(define (mi-cons x y) (lambda (m) (cond ((equal? m 'car) x) ((equal? m 'cdr) y) (else (error "mensaje no definido: " m)) )))

(define (mi-car pareja) (pareja 'car))

(define (mi-cdr pareja) (pareja 'cdr))

(define p (mi-cons (mi-cons 1 (mi-cons 3 4)) 2))> (mi-car (mi-cdr (mi-car p)))3

martes 8 de marzo de 2011