Tema 1: Introducción A. Chávez González y C. Graciani Dı́az Departamento de Ciencias de la Computación e Inteligencia Artificial Grado en Matemáticas. Informática. Curso 2010-2011 Programación Funcional Introducción Caracterı́sticas La Programación Funcional aparece como solución a necesidades en campos como IA, Cálculo simbólico, demostraciones de teoremas, procesamiento del lenguaje natural, ... Los cálculos se ven como una función matemática que hace corresponder entradas y salidas Método básico de computación: aplicación de funciones a sus argumentos Los bucles se modelan mediante recursión. Lenguaje de programación funcional: soporta y potencia el estilo funcional Funcional vs Imperativa Hoja de Cálculo: aproximación al lenguaje funcional Se especifica cada celda en términos de los valores de otras celdas. El objetivo es qué hay que calcular, no cómo No especificamos el orden en que deben calcularse las celdas, pero los cálculos respetan la dependencia entre operaciones No indicamos a la Hoja de Cálculo cómo manejar la memoria pero presenta un plano de celdas infinito y sólo utiliza la memoria de las celdas en uso Especificamos el valor de una celda por una expresión cuyas partes pueden evaluarse en cualquier orden en vez de una secuencia de comandos que calculan los valores Un lenguaje para PF Un lenguaje para Programación Funcional Caracterı́sticas de un buen lenguaje funcional Modo de evaluación (impaciente/perezosa) Que disponga de funciones de primer orden o orden superior Inferencia de tipos Polimorfismo frente a lenguajes no tipificados o con tipificación dinámica, como LISP o SCHEME Antecedentes Lenguajes de orden superior HOPE (Burstall et al., 1980) MIRANDA (Turner, 1985) SML (Milner et al., 1990) Todos han estado influenciados por MIRANDA. Cabe destacar ORWELL (Wadler, 1985). Recoge y amplı́a muchos conceptos introducidos por MIRANDA. “Introduction to Functional Programming” (Bird y Wadler, 1988) HASKELL HASKELL frente a otros lenguajes de orden superior Haskell es un estándar en la comunidad educativa hoy dia y en la enseñanza de la Programación Funcional Haskell B. Curry Reune las principales caracterı́sticas de la PF moderna. De ahı́ que se defina un estándar, Haskell 98 (Peyton Jones, 2003; Hudak y Fasel, 1999) Actualmente se diseñan gran cantidad de bibliotecas gráficas, de cálculo numérico, de acceso a BD, servidores web e interconexión con otros lenguajes Existencia de intérpretes y compiladores eficientes y de libre disposición. GOFER (Mark Jones, 1992) HUGS 98 (Jones, 1998) presenta caracterı́sticas adicionales, como ampliación del sistema de tipos y librerı́a de funciones gráficas Funciones Funciones Una función f es una correspondencia entre dos conjuntos inicial y final f:A→B f(x) 7−→ . . . Ejemplos: sucesor, sumaCuadrados (2 argumentos) y pi (constante) sumacuadrados : ZxZ → Z sumacuadrados(x, y) 7→ x2 + y2 Interesa evaluar la función para ciertos valores: ”El resultado de aplicar la función f al valor x es y ” Programas/Funciones Programar es dar al ordenador los pasos para resolver un problema La solución se calcula a partir de los datos, luego un programa se describe mediante funciones Programación funcional: ordenador = evaluador Prelude Ejemplos Prelude > 1 + 2 3 :: Integer Prelude > cos (2 * pi) 1.0 :: Double Prelude > [1..5] [1, 2, 3, 4, 5] :: [Integer] Prelude > mod 10 3 1 :: Integer Prelude > mod 10 (3 + 1) 2 :: Integer Reducción de Expresiones Reducción I El evaluador simplifica la expresión y muestra el resultado cuadrado :: Integer → Integer cuadrado x = x ∗ x Simplificación en varios pasos de reducción 2 + cuadrado3 =⇒ ! por la definición de cuadrado 2+3∗3 =⇒ ! por el operador (∗) 2+9 =⇒ ! por el operador (+) 11 Reducción II El evaluador simplifica la expresión y muestra el resultado Simplificación en varios pasos de reducción Un redex es cada parte de la expresión que pueda reducirse Forma normal Evaluador: mientras quede algún redex, reducir; cuando alcance la forma normal, mostrar el resultado Pero, ¿Qué ocurre si hay más de un redex? Ejemplo Reducción desde dentro cuadrado(cuadrado3 ) =⇒ ! por la definición de cuadrado cuadrado(3 ∗ 3) =⇒ ! por el operador (∗) cuadrado 9 =⇒ ! por la definición de cuadrado 9∗9 =⇒ ! por el operador (∗) 81 Reducción desde fuera cuadrado(cuadrado3 ) =⇒ ! por la definición de cuadrado (cuadrado 3) ∗ (cuadrado 3) =⇒ ! por la definición de cuadrado (3 ∗ 3) ∗ (cuadrado 3) =⇒ ! por el operador (∗) 9 ∗ (cuadrado 3) =⇒ ! por la definición de cuadrado 9 ∗ (3 ∗ 3) =⇒ ! por el operador (∗) 9∗9 =⇒ ! por el operador (∗) 81 Funciones estrictas y transparecia referencial Las funciones que para ser evaluadas necesitan que sus parámetros estén en forma normal se llaman estrictas. Ejs.: ∗ es estricto. cuadrado no es estricto. Sea cual sea el orden de reducción, el resultado final es el mismo. La reducción cambia la forma de una expresión, no su valor La transparencia referencial establece que una misma expresión denota siempre el mismo valor Si aparecen varios redexes, podemos elegir cualquiera sin que el resultado varı́e. Pero la elección del redex equivocado puede no conducir a la forma normal Ejemplo infinito :: Integer cero :: Integer =⇒ Integer infinito = 1 + infinito cero x = 0 Reducción desde dentro Reducción desde fuera cero infinito cero infinito =⇒ ! por la definición de infinito =⇒ ! por la definición de cero cero (1 + infinito) 0 =⇒ ! por la definición de infinito cero(1 + (1 + infinito)) =⇒ ! por la definición de infinito ... La estrategia utilizada para seleccionar el redex es crucial Un orden de reducción es una estrategia que indica qué redex hay que seleccionar en cada paso de reducción Orden de reducción aplicativo Seleccionar siempre el redex más interno y más a la izquierda Paso de parámetros por valor (call by value) Evaluadores estrictos o impacientes Problema: A veces se efectúan reducciones innecesarias cero(10 ∗ 4) =⇒ ! por el operador (∗) cero 40 =⇒ ! por la definición de cero 0 cero infinito Orden de reducción normal Seleccionar siempre el redex más externo y más a la izquierda Paso de parámetros por nombre (call by name) Evaluadores no estrictos Es normalizante Problema: Ciertas expresiones se reducen varias veces Ejemplo: cuadrado(cuadrado3 ) Evaluación perezosa Orden normal (paso por nombre): expresiones se reducen varias veces Solución: Evaluación perezosa (call by need) Consiste en utilizar paso por nombre y recordar los valores de los argumentos ya calculados para evitar recálculo No se utilizan más reducciones que con paso por valor, luego no es menos eficiente que ella y tiene las ventajas de paso por nombre. Haskell utiliza un evaluador perezoso Evaluación perezosa: Ejemplo cuadrado(cuadrado3 ) =⇒ ! por la definición de cuadrado a ∗ a donde a = cuadrado3 =⇒ ! por la definición de cuadrado a ∗ a donde a = b ∗ b donde b = 3 =⇒ ! por el operador (∗) a ∗ a donde a = 9 =⇒ ! por el operador (∗) 81 Representación perezosa de la función cuadrado Reducción perezosa de la función cuadrado El Lenguaje Haskell Caracterı́sticas Haskell es un lenguaje funcional puro, no estricto y fuertemente tipificado. Puro: Transparencia referencial. Una expresión denota siempre el mismo valor, en cualquier punto del programa en que aparezca. Razonamiento ecuacional utilizado en matemáticas. No estricto: orden no aplicativo. Evaluación perezosa: Normalizante Trabajo mı́nimo Eficiente Trabajo con estructuras de datos infinitas Tipificación fuerte: elementos clasificados en categorı́as. Sistema de tipos estático: comprobación en la compilación Sistema de tipos polimórfico: mas flexible Permite la sobrecarga: el mismo nombre Son aconsejables las anotaciones de tipo en los programas Sesiones con Haskell Un programa Haskell consiste en una o varias definiciones de funciones Declaración: tipo Definición: método de cómputo Ejemplo: -- Un ejemplo de fichero Haskell -- Calcula el siguiente entero al argumento sucesor :: Integer -> Integer sucesor x = x + 1 -- Calcula la suma de los cuadrados de sus argumentos sumaCuadrados :: Integer -> Integer -> Integer sumaCuadrados x y = x * x + y * y Sesiones con Haskell Haskell es un lenguaje fuertemente tipificado. El conjunto de valores, funciones y operadores predefinidos es ampliable, incluso se pueden definir nuevos tipos de datos sucesor :: Integer → Integer sucesor(x) = x + 1 Declaración de tipo, ecuación, método de cómputo, parámetro formal de la función Una función de dos argumentos sumaCuadrados :: Integer → Integer → Integer sumaCuadrados x y = x ∗ x + y ∗ y Main > sumaCuadrados (2 + 2) 3 25 :: Integer