Tema 2: Características de la programación funcional
|
|
|
- María Concepción María del Rosario Henríquez Castillo
- hace 9 años
- Vistas:
Transcripción
1 Tema 2: Características de la programación funcional Índice 1 Aproximación teórica a la programación funcional Programación declarativa El Lisp y el paradigma funcional El cálculo lambda Modelo de sustitución Aproximación práctica a la PF Características del paradigma funcional Definición y evaluación de funciones Uso de la recursión Funciones como tipo de datos primitivo Referencias...16
2 1. Aproximación teórica a la programación funcional 1.1. Programación declarativa El paradigma de programación funcional comparte, junto con el de programación lógica, características de programación declarativa. La característica fundamental del paradigma declarativo es que no existe la asignación ni el cambio de estado en un programa. Las variables son identificadores de valores que no cambian en toda la evaluación (como constantes definidas con un DEFINE de C). Sólo existen valores y expresiones matemáticas que devuelven nuevos valores a partir de los declarados. En los lenguajes imperativos, sin embargo, se realizan asignaciones que cambian el valor de una variable ya existente. Consideremos el siguiente ejemplo: 1. { int x = 1; 2. x = x+1; 3. int y = x+1; 4. { int x = y; 5. y = x+2; } 6. y = x;} En este fragmento de programa se mezclan instrucciones imperativas con instrucciones declarativas. Por ejemplo, las instrucciones 1, 3 y 4 son declarativas, ya que están definiendo una variable con un valor asociado (están dando un nombre a un valor). Sin embargo, las sentencias 2, 5 y 6 son imperativas, ya que están modificando el valor de una variable mediante asignaciones de nuevos valores. Otro elemento interesante del ejemplo es el ámbito de alcance (scope en inglés) de las declaraciones de las variables. Por ejemplo, la variable x declarada en la línea 4 tiene un ámbito distinto de la declarada en la línea 1. La x de la línea 5 es la declarada en la línea 4, mientras que la x de la línea 6 es la declarada en la línea 1. Dentro de un mismo ámbito podemos renombrar todas las ocurrencias de una variable sin que el programa cambie. Por ejemplo, el siguiente programa es equivalente al anterior: 1. { int x = 1; 2. x = x+1; 3. int y = x+1; 4. { int z = y; 5. y = z+2;} 6. y = x;} Page 2
3 Atención, pregunta Cuál es el ámbito de la variable y? Si renombráramos y por w, qué ocurrencias de y tendríamos que cambiar? Volviendo al asunto principal que nos concierne, los programas declarativos frente a los imperativos, para saber si un lenguaje es declarativo basta con comprobar el siguiente test: 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. Como consecuencia, los lenguajes declarativos tienen una interesante propiedad de optimización: si una expresión e aparece en varios lugares dentro de un mismo ámbito, sólo es necesario evaluarla una vez. Veamos por ejemplo, el siguiente programa: (define (f x)...) (+ (f 2) (f 2)) La expresión (f 2) se utiliza dos veces para sumar el resultado. En un paradigma declarativo esta expresión no va a cambiar de valor y va a devolver siempre el mismo valor. Por ello, es posible guardar el valor que devuelve en una nueva variable y sólo realizar la llamada una vez: (define (f x)...) (define y (f 2)) (+ y y) Una consecuencia muy importante de esta propiedad es que en un paradigma declarativo una función llamada con los mismos argumentos siempre devuelve el mismo resultado. Se hace notar Lo repetimos aquí, para que resalte más: en un paradigma declarativo (como por ejemplo, el paradigma funcional) una función llamada con los mismos argumentos siempre devuelve el mismo valor. Hemos dicho que en los lenguajes declarativos las variables denotan nombres asociados a valores. En los lenguajes imperativos, sin embargo, las variables denotan referencias a valores que existen en algún lugar del ordenador (estado) y que pueden ser cambiados con sucesivas instrucciones. Este es otro elemento que distingue los lenguajes imperativos de los declarativos. En los lenguajes declarativos no existe ese concepto de valor que reside en algún lugar del ordenador al que nos referimos mediante una variable. Page 3
4 Por ejemplo, veamos el siguiente programa imperativo: { int a[3] = {1, 5, 7} int *b = a; b[0] = 3; int c = a[0]+a[2];} En este programa, las variables a y b hacen referencia al mismo array (a la misma posición de memoria). De hecho, cuando en la tercera instrucción cambiamos el valor de la primera componente de b, también estamos modificando los valores a los que se refiere a, de forma que en la última instrucción c tomará el valor de 6. Al modificar b hemos modificado a ya que ambos se refieren (apuntan, si utilizamos una terminología de C) al mismo valor. Esto se denomina un efecto lateral. Un lenguaje declarativo no contiene referencias en el sentido del ejemplo anterior. Las referencias son exclusivas de los lenguajes imperativos. El uso de referencias permite que un mismo objeto (dato, valor) sea referenciado por más de un identificador y permite efectos laterales como el que hemos visto. Un lenguaje declarativo está libre de efectos laterales El Lisp y el paradigma funcional Una vez descrito el paradigma declarativo, vamos a comentar rápidamente algunas notas sobre la historia del Lisp. El Lisp es el lenguaje más importante del paradigma funcional. De él nacen una enorme variedad de dialectos, de los que Scheme es uno de los más extendidos en ámbitos académicos en la actualidad. El origen del Lisp se remonta al año 1956, en el que John McCarthy estaba buscando una solución para programar el computador IBM 704 ( en los primeros proyectos de inteligencia artificial. A finales de 1958 McCarthy, ya profesor de Ingeniería Electrónica y Marvin Minsky, profesor de matemáticas, ambos en el MIT, comenzaron el MIT Artificial Intelligence Project e iniciaron la implementación del Lisp. Entre los elementos que inspiraron el Lisp se encuentra el formalismo de programación funcional llamado cálculo lambda (ver siguiente sección). Uno de los factores que contribuyeron más al éxito del Lisp es su carácter pragmático. No se trata de un lenguaje puramente funcional ni declarativo, sino que es posible realizar sentencias imperativas en las que se modifican el valor de posiciones de memoria a las que hacen referencia variables. También sucede lo mismo en Scheme, y lo veremos en la segunda parte de la asignatura El cálculo lambda Page 4
5 La principal base teórica del paradigma funcional es el cálculo lambda (lambda calculus en inglés) desarrollado en la década de los 30 por Alonzo Church como modelo de computación con el mismo poder computacional que una Máquina de Turing. El cálculo lambda proporciona una notación muy simple (pero bastante críptica al mismo tiempo) de definición de funciones matemáticas. Sólo son necesarias tres reglas sintácticas para definir las expresiones del cálculo lambda: expresión-lambda ::= variable constante abstracción aplicación abstracción ::= lambda variable.expresión-lambda aplicación ::= (expresión-lambda)expresión-lambda La abstracción sirve para construir nuevas funciones matemáticas en base a expresiones previamente definidas. La aplicación, como su nombre indica, denota la aplicación de una función. Veamos algunos ejemplos simplificados (necesitaríamos algo más de tiempo para explicar la versión real). Una función es una construcción matemática que acepta una entrada y produce una salida. Supongamos que tenemos una función "pintado-amarillo" que produce las siguientes salidas a partir de las correspondientes entradas: cuadrado -> pintado-amarillo cuadrado coche -> pintado-amarillo coche mickey-mouse -> pintado-amarillo mickey-mouse Podemos usar el cálculo lambda para describir esta función: lambda x.pintado-amarillo x Esto es lo que se denomina una expresión-lambda. Si queremos aplicar la función a un argumento, aplicamos la siguiente sintaxis: (lambda x.pintado-amarillo x)cuadrado -> pintado-amarillo cuadrado El resultado de aplicar una expresión-lambda también puede ser una función, como en el siguiente ejemplo en el definimos un "constructor de funciones coloreadoras": lambda y.lambda x.pintado-y x Podemos usar esto para crear una función que pinta de color verde: (lambda y.lambda x.pintado-y x)verde -> lambda x.pintado-verde x Page 5
6 Las funciones también pueden ser argumentos de otras funciones, como esta función "aplicar-a-mickey-mouse": lambda f.(f)mickey-mouse Podemos entonces llamar a esta función con la función "pintado-amarillo" para pintar a mickey-mouse de amarillo: (lambda f.(f)mickey-mouse)lambda x.pintado-amarillo x -> (lambda x.pintado-amarillo x)mickey-mouse -> pintado-amarillo mickey-mouse La evaluación de las expresiones-lambda se basa en dos reglas de sustitución de argumentos formales por los argumentos reales, denominadas reducción-alfa y reducción-beta. No vamos a verlo en detalle, sólo comentar la regla de reducción-beta: La aplicación de una expresión-lambda a un argumento se consigue reemplazando en el cuerpo de la expresión-lambda su variable ligada por el argumento: (lambda x.p)q -> [Q/x]P donde [Q/x]P significa la substitución de x por Q en cualquier ocurrencia libre de x en P. Para más información sobre el cálculo lambda: An Introduction to Lambda Calculus and Scheme ( y lambda calculus en la Wikipedia ( Modelo de sustitución Durante la clase de hoy hemos estado hablando del paradigma declarativo, del paradigma funcional y hemos presentado un modelo formal que ha sido el origen del paradigma funcional. Vamos a terminar con el modelo computacional que va a explicar la semántica de los programas que escribamos dentro del paradigma funcional. Se trata del modelo de sustitución. Un modelo computacional es un formalismo (conjunto de reglas) que definen el funcionamiento de un programa. En el caso de Scheme, y de 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. Reglas para evaluar una expresión e de Scheme: 1. Si e es un valor primitivo, devolver ese mismo valor. Page 6
7 2. Si e es una variable, devolver su valor asociado. 3. 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. 4. Si e es una expresión del tipo (f arg1... argn), donde f 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. Para ilustrar estas regla, vamos a definir unas funciones: (define (double x) (+ x x)) (define (square y) (* y y)) (define (f z) (+ square (double z)) 1)) Y ahora vamos a ver qué ocurre cuando ejecutamos (f (+ 2 1)) utilizando el modelo de sustitución: 1. Evaluamos la expresión: f es un procedimiento; qué es (+ 2 1)? --> (f 3)) 2. Ahora tomamos el cuerpo de f y sustituimos 3 por z: (+ square (double 3)) 1) 3. Ahora evaluamos la expresión resultante: + denota el procedimiento suma, 1 se evalúa a 1. Qué es (square (double 3))? square es un procedimiento compuesto; y qué es (double 3)? double es otro procedimiento compuesto y 3 se evalúa a 3. Así que, una vez hemos evaluado todo, podemos empezar a aplicar los procedimientos. Empezamos por double sustituyendo el cuerpo de la función: (+ (square (+ 3 3)) 1) 4. Ahora, qué es (+ 3 3)? --> (+ (square 6) 1) 5. Ahora se sustituye el cuerpo de square: (+ (* 6 6) 1) 6. Qué es (* 6 6)? --> (+ 36 1) 7. Y (+ 36 1)? --> Orden de evaluación normal vs. de aplicación El ejemplo del modelo de sustitución que hemos visto se ha hecho utilizando el "orden de aplicación", donde se evalúa primero todos los procedimientos y argumentos antes de ejecutar la llamada a la función. Otra forma de evaluar expresiones es utilizando el "orden normal": expandir completamente los procedimientos hasta que todo está expresado mediante operaciones primitivas y autoevaluaciones, y entonces evaluar la expresión. El mismo problema de antes: (f (+ 2 1)) 1. Expandimos f, dejando (+ 2 1) sin evaluar: (+ (square (double (+ 2 1))) 1) Page 7
8 2. Ahora expandimos square: (+ (* (double (+ 2 1)) (double (+ 2 1))) 1) 3. Y ahora expandimos double: (+ (* (+ (+ 2 1) (+ 2 1)) (+ 2 1) (+ 2 1))) 1) 4. Por último, expandimos todo los operadores primitivos y autoevaluamos los valores. Se hace uno por uno (+ (* (+ 3 (+ 2 1)) (+ (+ 2 1) (+ 2 1))) 1) (+ (* (+ 3 3) (+ (+ 2 1) (+ 2 1))) 1) (+ (* (+ 3 3) (+ 3 (+ 2 1))) 1) (+ (* (+ 3 3) (+ 3 3))) 1) (+ (* 6 (+ 3 3)) 1) (+ (* 6 6) 1) (+ 36 1) 37 Hemos visto las dos formas de evaluación: con el orden aplicativo, evaluamos completamente todos los argumentos antes de aplicar el procedimiento. Mientras que en el orden normal, primero expandimos completamente los procedimientos hasta que todo está expresado mediante operaciones primitivas y valores. Entonces, en uno y en otro, podemos encontrar la solución de la expresión. Una consideración muy importante es que en programación funcional, donde una función siempre devuelve el mismo valor cuando es llamada con los mismos argumentos, el orden normal y el orden aplicativo siempre devolverán el mismo resultado. Sin embargo, esto no sucede cuando estamos en un lenguaje no funcional. Veamos el siguiente ejemplo: Vamos a definir una función que debería devolver siempre 0: (define (zero x) (- x x)) ; Esta función siempre ; debería devolver 0. Ahora vamos a evaluar (zero (random 10)) con orden aplicativo y con orden normal. Orden aplicativo: (zero (random 10)) (random 10) ==> 5 (zero 5) ----> (- 5 5) ==> 0 0 ; El orden de aplicación devuelve 0 Orden normal: (zero (random 10)) (zero (random 10)) ----> (- (random 10) (random 10)) (random 10) ==> 4 (random 10) ==> 8 Page 8
9 (- 4 8) ==> -4-4 ; El orden normal no La regla es que si estás haciendo programación funcional, obtienes las mismas respuestas sea cual sea el orden de evaluación. Por qué no sucede así en el caso de (zero (random 10))? Porque no es una función pura, ya que puede devolver valores distintos en distintas invocaciones. Otra diferencia entre la evaluación normal y la evaluación aplicativa es la eficiencia. Veamos un ejemplo. Intenta computar (square (square (+ 2 3))) en orden normal y de evaluación. En este caso el orden de aplicación es más eficiente proque sólo suma 2 y 3 una vez, no cuatro. (Pero más adelante, veremos que esto no es una regla general, a veces el orden normal es más eficiente). 2. Aproximación práctica a la PF 2.1. Características del paradigma funcional Uno de los primeros modelos computacionales, el cálculo lambda (Alonzo Church, 1930), está basado completamente en un enfoque funcional, en la creación y uso de funciones matemáticas. Este modelo computacional estableció las bases teóricas de lo que más tarde serían los lenguajes de programación funcionales. La popularidad del paradigma funcional se ha debido en gran medida al éxito del lenguaje de programación Lisp (y de sus dialectos, como Scheme). Tanto el Lisp como Scheme son lenguajes que se están utilizando en la actualidad (como ejemplo de uso del Lisp como lenguaje de programación de proyectos reales, leer la charla de Paul Graham ( titulada Beating the Averages ( en la que explica cómo utilizó el Lisp para construir Viaweb ( una de las primeras tiendas on-line adquirida en 1998 por Yahoo). Hay que resaltar que tanto Lisp como Scheme no son lenguajes funcionales puros (a diferencia de otros lenguajes como Haskell). En estas primeras clases vamos a usar únicamente las carracterísticas funcionales de Scheme. Dejaremos para más adelante sus construcciones imperativas. Entre las características del paradigma funcional destacamos: Programación declarativa Definición y evaluación de funciones Page 9
10 Uso de la recursión Funciones como datos primitivos Ya tratamos en la clase anterior algunos conceptos sobre programación declarativa, en la clase de hoy vamos a tratar las otras tres características. Lo vamos a hacer desde un punto de vista bastante práctico, con númerosos ejemplos en Scheme Definición y evaluación de funciones Cualquier lenguaje funcional permite la definición de nuevas funciones como forma de abstracción, y la evaluación de expresiones como forma de computación. Ya hemos visto cómo definir y evaluar funciones en Scheme: (define (cuadrado x) (* x x)) (+ (cuadrado 3) (cuadrado 2)) Estamos definiendo una función con un argumento formal (x) que tiene como cuerpo la expresión (* x x) y le estamos dando el nombre de cuadrado. Después evaluamos una expresión en la que llamamos a la función recién definida y a la función primitiva '+' Uso de la recursión Otro elemento común a todos los lenguajes funcionales es el uso de la recursión para expresar funciones que en otros lenguajes se expresan con iteraciones. Muchas veces es más sencillo y natural utilizar una recursión en la definición de una función. Veremos hoy algún ejemplo sencillo. En clases posteriores analizaremos más a fondo la recursión en Scheme. Factorial Un primer ejemplo es la típica función factorial que calcula el factorial de un número. Matemáticamente, el factorial de un número se puede expresar con la siguiente formulación: Esta expresión tiene una traducción directa en Scheme: (define (factorial x) (if (= x 0) 1 Page 10
11 (* x (factorial (- x 1))))) >(factorial 8) >(factorial 30) Sumatorio Otro ejemplo de función recursiva es el sumatorio desde un número inicial hasta un límite. Matemáticamente se expresa con la siguiente fórmula: En Scheme: (define (sumatorio min max) (if (> min max) 0 (+ min (sumatorio (+ 1 min) max)))) > (sumatorio 3 12) 75 Por último un ejemplo utilizando símbolos y las funciones que vimos en una clase anterior empty?, first, bf y equal?. Recordemos qué hace cada una de estas funciones: (empty? palabra): comprueba si palabra es una cadena vacía (first palabra): devuelve el primer carácter de un símbolo (como símbolo a su vez) (bf palabra): devuelve el resto de un símbolo, después de haber quitado su primer carácter (equal? pal1 pal2): comprueba si dos símbolos son iguales La función (elemento? x palabra) devuelve #t o #f dependiendo de si x es un símbolo que está dentro de palabra: (define (elemento? x palabra) (cond ((empty? palabra) #f) ((equal? x (first palabra)) #t) (else (elemento? x (bf palabra))))) > (elemento? 'a 'hola) #t Page 11
12 > (elemento? 'e 'cocodrilo) #f 2.4. Funciones como tipo de datos primitivo Otra característica fundamental de los lenguajes funcionales es que las funciones son consideradas un tipo de dato primitivo. Un tipo de dato primitivo es aquel que: puede ser el valor de una variable (en terminología de programación funcional: nombrado por un identificador) un argumento de una función el valor que devuelve una función componente de una estructura de datos mayor Por ejemplo, los números, los caracteres o las cadenas son datos primitivos en la mayor parte de lenguajes de programación. Sin embargo, resulta poco frecuente que podamos hacer todas estas cosas con una función o un procedimiento. Es una de las características más sorprendentes de los lenguajes funcionales: Una variable puede tener como valor un procedimiento Podemos definir una función que toma como argumentos otras funciones Podemos devolver un procedimiento como resultado de una llamada a otro procedimiento Podemos construir estructuras de datos que contengan procedimientos como elementos (listas de procedimientos, por ejemplo) Vamos a ver un ejemplo de cada una de estas características en Scheme: Una función puede ser nombrada con un identificador. Ya hemos visto algún ejemplo curioso de esto: (define suma +) suma >(suma 1 2 3) 6 (define + -) (+ 4 2) 2 (define + suma) Podemos comprobar en el ejemplo que los símbolos 'suma', '+' o '-' no son más que identificadores ligados a procedimientos. En Scheme cuando definimos una función con un nombre, la relación entre la función y el nombre es la misma que la relación entre una variable y un valor. El nombre de la función es Page 12
13 el identificador que está ligado al procedimiento. Una función puede ser el argumento de otra función. Por ejemplo, podemos defnir la siguiente función aplicar que toma como argumento una función f 2 argumentos y realiza la llamada a f con los 2 argumentos: (define (aplicar f x y) (f x y)) > (aplicar + 2 3) 5 > (aplicar * 2 3) 6 (aplicar word 'hola 'adios) holaadios En el siguiente ejemplo definimos una función que toma dos procedimientos unarios (de un argumento) f y g y los aplica a un número: (define (aplicar-2 f g x) (f (g x))) (define (5+ x) (+ 5 x)) (define (doble x) (* 2 x)) > (aplicar-2 5+ doble 8) 21 Una función puede ser el valor devuelto por otra función. Vamos a definir una función que devuelve otra función. La siguiente función hacer-suma1 define en su interior la función suma1 y la devuelve. (define (hacer-suma1) (define (suma1 x) (+ x 1)) suma1) (define f (hacer-suma1)) > (f 3) 4 Vemos que el resultado de la llamada a hacer-suma1 se guarda en la variable f y después comprobamos que realmente es una función que suma 1. Podemos complicar un poco más el ejemplo definiendo un parámetro con el número que queremos sumar en la función que devolvemos. Así, la función hacer-sumak construye otra función que suma el parámetro k al argumento x que se le pasa: (define (hacer-sumak k) (define (sumak x) Page 13
14 (+ x k)) sumak) (define g (hacer-sumak 8)) > (g 5) 13 Por último, una función puede ser parte de una estructura de datos mayor. Veamos un ejemplo que a primera vista puede parecer algo complicado (ya que mezclamos recursión y funciones como tipos de datos primitivos). Se trata de construir una función que recorra una lista de funciones unarias (se aplican a un único argumento) y las vaya aplicando a un argumento. Vamos a verlo paso a paso. Vamos a ver en primer lugar qué es eso de una lista de funciones unarias. (define (2+ x) (+ 2 x)) (define (10* x) (* 10 x)) (define (cuadrado x) (* x x)) (define lista-funcs (list cuadrado 2+ 10*)) La lista lista-funcs es una lista que contiene funciones (no identificadores). Vamos a comprobarlo. Si miramos su primer elemento el intérprete nos dice lo siguiente: > (car lista-funcs) #procedure:cuadrado Podemos probar qué ese primer elemento es un procedimiento aplicándolo a un número y viendo que devuelve su cuadrado: >((car lista-funcs) 3) 9 Podemos ahora hacer la función aplica-funcs que recorre la lista de funciones y las aplica a un número: (define (aplica-funcs lista x) (if (empty? (cdr lista)) ((car lista) x) ((car lista) (aplica-funcs (cdr lista) x)))) El caso base de la recursión es el caso en que la lista de funciones tiene un único argumento (eso es lo que significa (empty? (cdr lista))). En ese caso se devuelve el resultado de aplicar esa única función al número x. Page 14
15 En el caso general, aplicamos la primera función al resultado de la llamada recursiva de aplicar el resto de funciones al número x Lambda en Scheme Los tipos de datos primitivos se pueden manejar directamente en los lenguajes de programación, sin darles nombre (asignarlos a variables). Por ejemplo, cuando queremos llamar a una función cualquiera (como cuadrado) con el número "4" como argumento, escribimos directamente "4" y de esa forma nos referimos a ese número: "4": (cuadrado 4) No hace falta hacer: (define cuatro 4) (cuadrado cuatro) Hemos dicho que las funciones son en Scheme tipos de datos primitivos. Cumplen entonces la propiedad anterior? Es posible usar una función sin darle un nombre? La respuesta es que sí, utilizando la forma especial lambda. La sintaxis de lambda es: (lambda (<arg1>... <argn>) <cuerpo>) La forma especial lambda construye una función sin nombre y la devuelve como resultado. Para definir una función son necesarios dos elementos: sus argumentos y su cuerpo. Estos dos elementos son los que se definen a continuación de la palabra lambda. Así, por ejemplo, en la siguiente expresión: (lambda (x) (* x x)) se define una función que tiene un único argumento (x) y que tiene como cuerpo la expresión (* x x). Es la función cuadrado. Si ejecutamos esa expresión en el intérprete de Scheme veremos que el resultado de su evaluación es un procedimiento: >(lambda (x) (* x x)) #procedure:3:2 Con ese procedimiento que nos devuelve Scheme (el procedimiento llamado con el críptico nombre de #procedure:3:2) podemos hacer bastantes cosas. Algunos ejemplos: 1. Podemos darle un nombre y obtener una función con nombre que después podremos usar: Page 15
16 > (define cuadrado (lambda (x) (* x x))) > (cuadrado 3) 9 2. Pasarlo como argumento de otra función que admite otras funciones como parámetro: >(define (aplicar-2 f g x) (f (g x))) >(define (suma-5 x) (+ 5 x)) >(aplicar-2 suma-5 (lambda (x) (* x x)) 3) Podemos evaluarlo inmediatamente poniendo un paréntesis de apertura (recordad lo que comentamos la primera semana de clase de que los paréntesis de apertura "(" servían para lanzar funciones o formas especiales que hay a continuación de ellos): >((lambda (x) (* x x)) 3) 9 3. Referencias Para saber más de los temas que hemos tratado en esta clase puedes consultar las siguientes referencias: Structure and Interpretation of Computer Programs ( Abelson y Sussman, MIT Press 1996 (pp ). Disponible biblioteca politécnica (acceso al catálogo ( ) Encyclopedia of Computer Science (Wiley, 2000). Disponible en la biblioteca politécnica (POE R0/E/I/ENC/RAL). Consultar las entradas: Functional programming Lambda calculus Lisp List processing Concepts in Programming Languages, John C. Mitchel, Cambridge University Press, Cap. 3, 4.2 y 4.4. Disponible en la biblioteca politécnica (POE I.062/MIT/CON). Lambda calculus ( (Wikipedia) Functional programming ( (wikipedia) Beating the Averages ( un ensayo de Paul Graham ( Page 16
17 Page 17
Tema 3: Características de la programación funcional. Sesión 5: El paradigma funcional (1)
Tema 3: Características de la programación funcional Sesión 5: El paradigma funcional (1) 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
Tema 6: Estructuras de datos recursivas
Tema 6: Estructuras de datos recursivas Índice 1 Listas jerárquicas...2 2 Árboles binarios... 4 3 Árboles genéricos...7 4 Referencias...10 1. Listas jerárquicas Las listas tienen la propiedad de la clausura
Tema 3: Características de la programación funcional
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-
Tema 2: Introducción a Scheme. Sesión 4: Introducción a Scheme (2)
Tema 2: Introducción a Scheme Sesión 4: Introducción a Scheme (2) Referencias DrRacket (http://racket-lang.org/) A brief tour of DrScheme (http://www.plt-scheme.org/software/drscheme/ tour/) Structure
CAPÍTULO IV: 4.1 Introducción a la. Programación Funcional
CAPÍTULO IV: Programación Funcional 4.1 Introducción a la Programación Funcional 1 Programación Funcional Paradigma diferente a los imperativos, que se aleja de la máquina de von Neumann Basado en funciones
Tema 4: Programación funcional avanzada en Scheme
Tema 4: Programación funcional avanzada en Scheme Índice 1 Let... 2 2 Let*... 5 3 Letrec... 5 4 Quote...6 5 Eval... 7 6 Datos compuestos: parejas...8 7 Los datos compuestos pueden ser funciones...11 8
Lenguajes de Programación Programación funcional
Lenguajes de Programación Programación funcional Roberto Bonvallet Departamento de Informática Universidad Técnica Federico Santa María Concepto de función En el paradigma imperativo: Una función es una
Tema 3: Recursión. Índice
Índice 1 Recursión... 2 2 Confía en la recursión... 2 3 El coste espacial de la recursión... 5 4 Procesos recursivos e iterativos... 7 4.1 Ejemplos...10 5 Referencias...12 1. Recursión Ya hemos visto algunos
Tema 3: Programación funcional
Tema 3: Programación funcional Contenidos 5. Funciones como tipos de datos de primera clase 5.1. Forma especial lambda 5.2. Las funciones son objetos de primera clase 5.3. Funciones de orden superior 6.
Programación Funcional
Alberto Pardo Marcos Viera Instituto de Computación, Facultad de Ingeniería Universidad de la República, Uruguay Objetivo del curso Este es un curso introductorio de programación funcional (PF) Veremos
GUÍA BÁSICA DE SCHEME v.4
Esta guía básica pretende ser una introducción elemental al lenguaje de programación Scheme. Se presenta como una guía de comienzo rápido de tal forma que permita conocer de una forma muy esquemática los
Programación Funcional en LISP Lógica para Ciencias de la Computación
Programación Funcional en LISP Lógica para Ciencias de la Computación Primer Cuatrimestre de 2009 Material Adicional Introducción A lo largo de la carrera estudiaremos diversos paradigmas de programación:
Aplicación de la Inducción Matemática Programación Funcional. Julio Ariel Hurtado Alegría Departamento de Sistemas Universidad del Cauca
Aplicación de la Inducción Matemática Programación Funcional Julio Ariel Hurtado Alegría Departamento de Sistemas Universidad del Cauca Motivación Programación Imperativa Declarativa Procedimental Ejemplo:
Tema 3. Listas Recursión sobre datos
Tema 3 Listas Recursión sobre datos José A. Alonso M. José Hidalgo Álvaro Romero Dpto. Ciencias de la Computación e Inteligencia Artificial UNIVERSIDAD DE SEVILLA Informática ListasRecursión sobre datos
Entendiendo expresiones lambda en C# con Mono
Entendiendo expresiones lambda en C# con Mono Martín O. Márquez Introducción La programación imperativa es uno de los paradigmas de computación más ampliamente utilizados por la mayoría
Laboratorio Análisis Lógico Práctica 1
Laboratorio Análisis Lógico Práctica 1 Pedro Arturo Góngora Luna 1 1 Introducción 1.1 Haskell y la programación funcional En la década de los 30 s, Alonzo Church desarrolló un lenguaje formal llamado cálculo
Tema 3: Programación funcional
Tema 3: Programación funcional Contenidos 1. El paradigma de Programación Funcional 1.1 Definición y orígenes del paradigma funcional 1.2. Programación declarativa 1.3. Valores y referencias 1.4. Modelo
Programación Funcional Lisp-DrScheme Primera Parte. Dr. Oldemar Rodríguez Rojas Escuela de Informática Universidad de Nacional
Programación Funcional Lisp-DrScheme Primera Parte Dr. Oldemar Rodríguez Rojas Escuela de Informática Universidad de Nacional Programación Funcional! La programación funcional es un paradigma de programación
Paradigmas de lenguajes de programación. Introducción a la programación imperativa. Lenguaje C. Programación imperativa
Paradigmas de lenguajes de programación Introducción a la programación imperativa Algoritmos y Estructuras de Datos I Paradigma: Definición del modo en el que se especifica el cómputo (que luego es implementado
Tema 4.- Recursión e iteración
UNIVERSIDAD DE CÓRDOBA ESCUELA POLITÉCNICA SUPERIOR DE CÓRDOBA DEPARTAMENTO DE INFORMÁTICA Y ANÁLISIS NUMÉRICO PROGRAMACIÓN DECLARATIVA INGENIERÍA INFORMÁTICA ESPECIALIDAD DE COMPUTACIÓN CUARTO CURSO PRIMER
UNIDAD IV Programación Funcional. Lic. Jesús Germán Andrés PAUTSCH - FCEQyN - UNaM
UNIDAD IV Programación Funcional Porqué? 2 Introducción Porque aprender programación funcional? - Recursión - Abstracción funcional - Funciones de primer orden Estos conceptos se han incorporado en la
Algoritmos y programas. Algoritmos y Estructuras de Datos I
Algoritmos y programas Algoritmos y Estructuras de Datos I Primer cuatrimestre de 2012 Departamento de Computación - FCEyN - UBA Programación funcional - clase 1 Funciones Simples - Recursión - Tipos de
Programación Declarativa
Programación Declarativa Tema 2: LISP (SCHEME) 2 Tema 2: LISP (SCHEME) Introducción Representación de Datos Definición de Funciones Predicados Listas 3 Introducción (I) SCHEME es un dialecto de LISP (LISt
n! = 1 2 n 0! = 1 (n+1)! = (n + 1) n!
Capítulo 3 Recursión La recursión es un estilo autoreferencial de definición usado tanto en matemática como en informática. Es una herramienta de programación fundamental, particularmente importante para
GENERACIÓN DE CÓDIGO INTERMEDIO EJEMPLOS PARA DISTINTAS ESTRUCTURAS DE DATOS
Todos los derechos de propiedad intelectual de esta obra pertenecen en exclusiva a la Universidad Europea de Madrid, S.L.U. Queda terminantemente prohibida la reproducción, puesta a disposición del público
Tema 2.- Expresiones y funciones
UNIVERSIDAD DE CÓRDOBA ESCUELA POLITÉCNICA SUPERIOR DE CÓRDOBA DEPARTAMENTO DE INFORMÁTICA Y ANÁLISIS NUMÉRICO PROGRAMACIÓN DECLARATIVA INGENIERÍA INFORMÁTICA ESPECIALIDAD DE COMPUTACIÓN CUARTO CURSO PRIMER
Clase 1 de prácticas: Introducción a Scheme
Clase 1 de prácticas: Introducción a Scheme Índice 1 Ejercicio 1... 2 2 Ejercicio 2... 2 3 Ejercicio 3... 2 4 Ejercicio 4... 3 5 Ejercicio 5... 3 6 Ejercicio 6... 4 7 Ejercicio 7 (ampliación)...4 8 Ejercicio
Introducción a Haskell. Cecilia Manzino
Paradigmas de programación Un paradigma de programación representa un estilo particular o filosofía para la construcción del software. Los más comunes dan lugar a los siguientes tipos de programación:
PROGRAMA DE CURSO. Horas de Trabajo Personal ,5 5,5
Código Nombre CC4101 Lenguajes de Programación Nombre en Inglés Programming Languages SCT PROGRAMA DE CURSO Unidades Docentes Horas de Cátedra Horas Docencia Auxiliar Horas de Trabajo Personal 6 10 3 1,5
Apunte Laboratorio ALPI - El lenguaje de programación Pascal
Apunte Laboratorio ALPI - El lenguaje de programación Pascal 1 2 ÍNDICE GENERAL Índice 1. Estructura de un Programa en Pascal 3 2. Sintaxis de Pascal 4 2.1. Uso de mayúsculas.....................................
Fundamentos de la POO 1
Fundamentos de la POO 1 La correcta aplicación de los conocimientos de clases y objetos nos permitirán llegar a los objetivos planteados y a generar programas que puedan ser fáciles de comprender para
Tema 1: Introducción a la programación funcional
Programación declarativa (2009 10) José A. Alonso Jiménez Grupo de Lógica Computacional Departamento de Ciencias de la Computación e I.A. Universidad de Sevilla 2 / 21 3 / 21 en Haskell En Haskell, una
Introducción a la programación. Cecilia Manzino
Paradigmas Un paradigma es un modelo o patrón en cualquier disciplina científica. Un paradigma de programación representa un estilo de programación en cual se escriben soluciones a problemas en términos
CONCEPTO Y DEFINICIÓN DE CLASE EN JAVA. OBJETOS DEL MUNDO REAL Y ABSTRACTOS. EJEMPLOS. EJERCICIO (CU00644B)
APRENDERAPROGRAMAR.COM CONCEPTO Y DEFINICIÓN DE CLASE EN JAVA. OBJETOS DEL MUNDO REAL Y ABSTRACTOS. EJEMPLOS. EJERCICIO (CU00644B) Sección: Cursos Categoría: Curso Aprender programación Java desde cero
Lenguajes de Programación
Lenguajes de ción Bloque 1. Complemento a Tema 1 1. Historia 2. Paradigmas de programación 3. Fases creación de un programa 4. Traducción: compilación e interpretación 1ª Generación Ordenadores sólo entienden
Inducción, Recursión y Alcance. Inducción, Recursión y alcance. Inducción, Recursión y Alcance. Inducción, Recursión y Alcance
Inducción, Recursión y alcance Especificación inductiva de tipos de datos Tipo de datos: Conjunto de valores Conjunto de operaciones sobre dichos valores ejemplo: Sea S el conjunto más pequeño tal que:
Tema: Funciones, Procedimientos y Recursividad en C#.
2 Programación I Programación I. Guía 6 3 Facultad: Ingeniería Escuela: Ingeniería en Computación Asignatura: Programación I Tema: Funciones, Procedimientos y Recursividad en C#. Objetivos Utilizar la
Introducción a c++ Introducción a la programación EIS Informática III
Introducción a c++ Un lenguaje de programación es un lenguaje formal diseñado para realizar procesos que pueden ser llevados a cabo por máquinas como las computadoras. Pueden usarse para crear programas
! Qué es la POO?! Un paradigma de programación. ! No hay paradigmas mejores ni peores! Todos tienen sus ventajas e inconvenientes
Introducción Programación orientada a objetos Curso INEM. Programación en Java Santiago Muelas Pascual [email protected]! Qué es la POO?! Un paradigma de programación! Un paradigma es una forma de afrontar
Tema: Funciones, Procedimientos y Recursividad en C#.
Tema: Funciones, Procedimientos y Recursividad en C#. Objetivos Programación I, Guía 6 1 Utilizar la sintaxis de las funciones definidas por el usuario (programador) para resolver problemas. Identificar
Tema: Funciones, Procedimientos y Recursividad en C#.
Tema: Funciones, Procedimientos y Recursividad en C#. Objetivos Programación I, Guía 7 1 Facultad: Ingeniería Escuela: Ingeniería en Computación Asignatura: Programación I Utilizar la sintaxis de las funciones
Tema 3.- Predicados y sentencias condicionales
UNIVERSIDAD DE CÓRDOBA ESCUELA POLITÉCNICA SUPERIOR DE CÓRDOBA DEPARTAMENTO DE INFORMÁTICA Y ANÁLISIS NUMÉRICO PROGRAMACIÓN DECLARATIVA INGENIERÍA INFORMÁTICA ESPECIALIDAD DE COMPUTACIÓN CUARTO CURSO PRIMER
Tema 4. Funciones de orden superior
Programación Declarativa Haskell Informática Sistemas Curso 2003-2004 Pepe Gallardo Universidad de Málaga Tema 4. Funciones de orden superior 4.1 Funciones de orden superior 4.2 Expresiones lambda 4.3
PARADIGMAS DE PROGRAMACIÓN CALCULO LAMBDA CALCULO LAMBDA
PARADIGMAS DE PROGRAMACIÓN 2006 CALCULO LAMBDA CALCULO LAMBDA El cálculo lambda fue desarrollado por Alonso Church en la década del 30 con el objeto de dar una teoría general de las funciones. El cálculo
Tema: Funciones, Procedimientos y Recursividad en C#.
Programación I, Guía 6 1 Tema: Funciones, Procedimientos y Recursividad en C#. Objetivos Utilizar la sintaxis de las funciones definidas por el usuario (programador) para resolver problemas. Identificar
TEMA 5: Subprogramas, programación modular
TEMA 5: Subprogramas, programación modular 5.1.-Definición de módulo. Programación modular La programación modular está basada en la técnica de diseño descendente, que como ya vimos consiste en dividir
Unidad II: Análisis semántico
Unidad II: Análisis semántico Se compone de un conjunto de rutinas independientes, llamadas por los analizadores morfológico y sintáctico. El análisis semántico utiliza como entrada el árbol sintáctico
Programación Declarativa Curso
Programación Declarativa Curso 2004-2005 Ingeniería Técnica en Informática de Gestión Departamento de Lenguajes y Ciencias de la Computación Universidad de Málaga Programación Declarativa 1 Profesorado
Tipos algebraicos y abstractos. Algoritmos y Estructuras de Datos I. Tipos algebraicos
Algoritmos y Estructuras de Datos I 1 cuatrimestre de 009 Departamento de Computación - FCEyN - UBA Programación funcional - clase Tipos algebraicos Tipos algebraicos y abstractos ya vimos los tipos básicos
Informática Haskell Matemáticas Curso Pepe Gallardo Universidad de Málaga. Temario
Informática Haskell Matemáticas Curso 2004-2005 Pepe Gallardo Universidad de Málaga Temario 1 Introducción y semántica operacional 2 Tipos predefinidos 3 Patrones y Definiciones de Funciones 4 Funciones
Tema 03: Programación estructurada
Tema 03: Programación estructurada M. en C. Edgardo Adrián Franco Martínez http://www.eafranco.com [email protected] @edfrancom edgardoadrianfrancom Estructuras de datos (Prof. Edgardo A. Franco) 1 Contenido
Autoestudio 2: Variables y Operadores
Autoestudio 2: Variables y es Componentes de un programa Cuando escribimos en un lenguaje de programación tenemos que entender la sintaxis del lenguaje. A continuación empezaremos con la sintaxis básica
FUNCIONES JAVASCRIPT. CONCEPTO. PARÁMETROS O ARGUMENTOS Y TIPOS. PASO POR VALOR. RETURN. EJEMPLOS. (CU01122E)
APRENDERAPROGRAMAR.COM FUNCIONES JAVASCRIPT. CONCEPTO. PARÁMETROS O ARGUMENTOS Y TIPOS. PASO POR VALOR. RETURN. EJEMPLOS. (CU01122E) Sección: Cursos Categoría: Tutorial básico del programador web: JavaScript
Funciones como parámetros, funciones como resultados. Introducción a la Computación Patricia Borensztejn Clase 26
Funciones como parámetros, funciones como resultados Introducción a la Computación Patricia Borensztejn Clase 26 Funciones de orden superior Se llama así a la técnica que permite pasar funciones como parámetros
Lenguaje de programación S (Davis/Sigal/Weyuker) Lógica y Computabilidad. Ejemplo 1. Ejemplo 2
Lógica y Computabilidad Verano 2011 Departamento de Computación - FCEyN - UBA Computabilidad - clase 4 Lenguaje S, estado, descripción instantánea, cómputo, funciones parciales computables, minimización
Tema 7: Programación imperativa. Sesión 23: Programación imperativa (4)
Tema 7: Programación imperativa Sesión 23: Programación imperativa (4) Indice Historia de la programación imperativa Características principales Datos mutables en Scheme y en Scala Estructuras de control
Lenguajes funcionales: λ-cálculo
Lenguajes funcionales: λ-cálculo λ-cálculo (Church 1933) Cálculo para el estudio formal del comportamiento de las funciones Sintaxis: λ expresiones Reglas de reducción de λ expresiones Método matemático
Tema 2: Introducción a la programación con Haskell
Programación declarativa (2010 11) José A. Alonso Jiménez Grupo de Lógica Computacional Departamento de Ciencias de la Computación e I.A. Universidad de Sevilla 2. 4. 2 / 26 El sistema GHC El sistema GHC
Tema 2: Introducción a la programación con Haskell
Tema 2: Introducción a la programación con Haskell Programación declarativa (2009 10) José A. Alonso Jiménez Grupo de Lógica Computacional Departamento de Ciencias de la Computación e I.A. Universidad
ESCUELA SUPERIOR POLITECNICA DEL LITORAL
ESCUELA SUPERIOR POLITECNICA DEL LITORAL LENGUAJES DE PROGRAMACIÓN UNIDAD ACADÉMICA: CARRERA: ESPECIALIZACIÓN: ÁREA: TIPO DE MATERIA: EJE DE FORMACIÓN: Facultad de Ingeniería en Electricidad y Computación
Programación MODULAR: Subalgoritmos - funciones y procedimientos
Programación MODULAR: Subalgoritmos - funciones y procedimientos Uno de los métodos fundamentales para resolver un problema es dividirlo en problemas más pequeños, llamados subproblemas. Estos problemas
ING1310 Introducción a la Computación. Python. Conceptos Básicos. Carlos Reveco
ING1310 Introducción a la Computación Python Conceptos Básicos Carlos Reveco [email protected] [email protected] Facultad de Ingeniería/Universidad de los Andes/Chile Rev : 254 C.Reveco Facultad
Funciones y subrutinas
Algorítmica y Lenguajes de Programación Funciones y subrutinas Funciones y subrutinas. Introducción El diseño descendente permite obtener un programa que resuelva un problema dividiendo este en subproblemas
Es un conjunto de palabras y símbolos que permiten al usuario generar comandos e instrucciones para que la computadora los ejecute.
Los problemas que se plantean en la vida diaria suelen ser resueltos mediante el uso de la capacidad intelectual y la habilidad manual del ser humano. La utilización de la computadora en la resolución
