Un lenguaje funcional avanzado: Haskell Salvador Lucas Alba Departamento de Sistemas Informáticos y Computación Universidad Politécnica de Valencia http://www.dsic.upv.es/~slucas
Objetivos Introducir la sintaxis básica de Haskell Aprender a utilizar el intérprete Hugs para ejecutar programas escritos en Haskell
Desarrollo Introducción a Haskell Nivel léxico Expresiones Declaraciones
Desarrollo Introducción a Haskell Nivel léxico Expresiones Declaraciones
Introducción a Haskell Características principales Permite al usuario definir sus propios tipos y estructuras de datos Dispone de los tipos predefinidos usuales (booleanos, enteros, caracteres, cadenas, …) con las operaciones predefinidas habituales Soporta distintos niveles de polimorfismo: Polimorfismo paramétrico Polimorfismo ‘ad-hoc’ (sobrecarga)
Introducción a Haskell Características principales Un programa es un conjunto de definiciones de función realizadas mediante ecuaciones condicionales Pueden emplearse expresiones let y where así como las reglas de ‘layout’ Funciones de orden superior La evaluación de expresiones es ‘perezosa’ (lazy)
Introducción a Haskell Características principales Los programas pueden organizarse en modulos o ‘librerías’ Los programas Haskell suelen llevar la extensión ‘hs’. El módulo Prelude.hs contiene definiciones de tipos y funciones que pueden utilizarse de forma inmediata en cualquier programa
Introducción a Haskell Module ProgHaskell Importación/Exportación de módulos Definición de tipos y estructuras de datos Definición de funciones
Introducción a Haskell Prelude.hs Definición de tipos y estructuras de datos Definición de funciones
Desarrollo Introducción a Haskell Nivel léxico Expresiones Declaraciones
Nivel léxico Identificadores Un identificador Haskell consta de una letra seguida por cero o más letras, dígitos, subrayados y comillas simples. Los identificadores son case-sensitive (el uso de minúsculas o mayúsculas importa)
Nivel léxico Identificadores Como en todos los lenguajes, hay ‘palabras reservadas’: case, data, deriving, do, else, if, import, let, module, of, then, type, where… La letra inicial del identificador distingue familias de identificadores: empiezan por Mayúscula los tipos y constructores de datos Minúscula los nombres de función y variables
Nivel léxico Identificadores Ejemplo: Bool, Int, Char, String (predef) data Color = Red | Green | Blue data Laboral = Lu | Ma | Mi | Ju | Vi data TreeInt = L Int | B TreeInt TreeInt data Tree t = L t | B (Tree t) (Tree t) Constructores de tipos Mayusc. Minusc. Variables de tipo Constructores de datos
Nivel léxico Ejemplo: fact n | n==0 = 1 | n>0 = n*fact (n-1) length [] = 0 length (x:xs) = 1+length xs Nombres de función Mayusc. Constructores de datos Minusc. Variables
Nivel léxico Operadores Se pueden especificar operadores: cadenas de símbolos escogidos entre !, #, $, %, &, *, +, -, ., /, <, =, >, ?, @, \, :,… Ejemplo: +!+, <&, <=>, … Si queremos utilizar el operador como constructor de datos debe empezar por ‘:’
Nivel léxico Comentarios Un trozo de texto en un programa puede ‘comentarse’ encerrándolo entre {- -} o bien, si es una sola línea, precediéndolo de --
Nivel léxico Números Los enteros se escriben de la manera habitual: 0, 45, -3452, 2147493647 Los números en coma flotante también: 0.31426, -23.12, 567.347, 4523.0 231.61e7, 231.6e-2, -3.412e03
Nivel léxico Caracteres Los caracteres se escriben así: ‘a’, ‘b’, ..., ‘A’, ‘B’, ..., ‘1’, ‘2’, ... ‘\a’, ‘\b’, ‘\f’, ‘\n’, ‘\r’, ... ‘\BEL’, ‘\BS’, ‘\FF’, ‘\LF’, ‘\CR’, ... ‘\7’, ‘\8’, ‘\12’, ‘\10’, ‘\13’, ... ‘\o7’, ‘\o10’, ‘\o14’, ‘\o12’, ‘\o15’ ‘\x7’, ‘\x8’, ‘\xC’, ‘\xA’, ‘\xD’, ...
Nivel léxico Cadenas Los cadenas de caracteres son secuencias de caracteres entre comillas dobles: “”, “1&bA”, “Esta frase \10ocupa dos lineas”
Desarrollo Introducción a Haskell Nivel léxico Expresiones Declaraciones
Expresiones Llamada a una función Dado un nombre de función f y expresiones e1, e2, …, ek la expresión ( f e1 e2 ··· ek ) representa la llamada a la función f con argumentos e1, e2, …, ek ¡Paréntesis externos! ¡No hay ‘comas’!
Expresiones Llamada a una función Ejemplos: (fact 10) (length “abcd”)
Expresiones Llamada a una función También es válido: fact 10 length “abcd” fact (length “abcd”)
Expresiones Utilización de operadores Dado un operador (binario) Å y expresiones e1, e2 la expresión (e1 Å e2) representa la aplicación del operador Å a sus argumentos e1, e2
Expresiones Utilización de operadores Ejemplos: (10 + 3) (“abcd” ++ “123”) ((a:“bcd” ) ++ “123”)
Expresiones Utilización de operadores También es válido: 10 + 3 “abcd” ++ “123” (a:“bcd” ) ++ “123”
Expresiones Por supuesto, se pueden combinar fact (10 + 3) length (“abcd” ++ “123”) length ((a:“bcd” ) ++ “123”)
Expresiones Condicionales La expresión condicional puede utilizarse en su sintaxis ‘infija’: fact n = if n==0 then 1 else n*(fact (n-1))
Expresiones Listas Por su frecuente uso en programación funcional, se han desarrollado (y se admiten) distintas notaciones para expresar listas: 1:2:3:[] (igual a 1:(2:(3:[])) ) [1,2,3] 1:[2,3] corresponden a la misma lista (:) es asociativo por la derecha
Expresiones Listas La notación de listas aritméticas permite expresar secuencias de enteros: [2..10] es [2,3,4,5,6,7,8,9,10] [1..] es [1,2,3,4,... [1,3..10] es [1,3,5,7,9] [1,3..] es [1,3,5,7,9,...
Expresiones Listas También se puede utilizar para expresar secuencias de caracteres o booleanos: [’a’..’e’] es “abcde” [False ..] es [False,True] [’a’,’e’..’z’] es “aeimquy”
Expresiones Expresiones lambda Una función f se describe mediante una expresión lambda de la forma \ x1 · · · xk -> e Las variables x1, ..., xk son distintas entre sí y las únicas que aparecen en la expresión e
Expresiones Expresiones lambda Ejemplo \ x y -> x+y \ x -> 2*x \ x -> True \ m n -> B (L m) (L n)
Desarrollo Introducción a Haskell Nivel léxico Expresiones Declaraciones
Tipos definidos por el usuario Declaraciones Tipos definidos por el usuario Los tipos ‘de usuario’ se definen junto con los valores que éstos contienen Ejemplos: data Color = Red | Green | Blue data Laboral = Lu | Ma | Mi | Ju | Vi data TreeInt = L Int | B TreeInt TreeInt data Tree t = L t | B (Tree t) (Tree t)
Tipos definidos por el usuario Declaraciones Tipos definidos por el usuario Los valores se obtienen considerando la definición de tipo como una gramática: Los constructores de datos son símbolos terminales Los constructores de tipo son símbolos no terminales Los valores del tipo son los términos del lenguaje generado por la gramática
Tipos definidos por el usuario Declaraciones Tipos definidos por el usuario Ejemplo: Int := 0 | 1 | 2 | 3 | ··· | -1 | -2 | -3 | ··· TreeInt := L Int | B TreeInt TreeInt Valores de este tipo son: L 1, L -10, B (L 1) (L 10), B (B (L 1) (L1)) (L -1)
Tipos definidos por el usuario Declaraciones Tipos definidos por el usuario Ejemplo de valor del tipo TreeInt 1 4 2 3 (B (L 1) (B (B (L 2) (L 3)) (L 4)))
Tipos definidos por el usuario Declaraciones Tipos definidos por el usuario Las siguientes expresiones: L (1+1) B (B (L 1) (L (length “ab”))) (L (fact 2)) son del tipo TreeInt, pero no son valores (contienen símbolos no constructores)
Definición de funciones Declaraciones Definición de funciones En los lenguajes funcionales, lo normal es definir las funciones mediante ecuaciones empleando (y combinando) distintas técnicas: parámetros formales guardas ajuste de patrones distinción de casos cláusulas where
Definición de funciones Parámetros formales Una función f se describe mediante ecuaciones de la forma: f x1 · · · xk = r Las variables x1, ..., xk son distintas entre sí y las únicas que aparecen en la parte derecha r
Definición de funciones Parámetros formales Ejemplos: doble x = x+x triple x = 3*x seisveces x = doble (triple x) fact n = if n==0 then 1 else n*fact (n-1)
Definición de funciones Parámetros formales Ejemplos: doble x = x + x triple x = 3 * x Funciones primitivas
Definición de funciones Parámetros formales Ejemplos: doble x = x+x triple x = 3*x seisveces x = doble (triple x) Otras funciones de usuario
Definición de funciones Parámetros formales Ejemplos: doble x = x+x triple x = 3*x seisveces x = doble (triple x) fact n = if n==0 then 1 else n*fact (n-1) Recursividad
Definición de funciones Parámetros formales y guardas Una función f se describe mediante ecuaciones de la forma: f x1 · · · xk | c = r donde c es una expresión booleana
Definición de funciones Parámetros formales y guardas Ejemplos: fact n | n==0 = 1 | n>0 = n*fact (n-1) sign x | x<0 = neg | x==0 = cero | x>0 = pos
Definición de funciones Parámetros formales y guardas Ejemplos: fact n | n==0 = 1 | n>0 = n*fact (n-1) sign x | x<0 = neg | x==0 = cero | x>0 = pos Guardas
Definición de funciones Ajuste de patrones Una función f se describe mediante ecuaciones de la forma: f p1 · · · pk = r Los patrones p1, ..., pk son términos constituidos por constructores de datos y variables
Definición de funciones Ajuste de patrones Ejemplos: length [] = 0 length (x:xs) = 1+length xs data Nat = Cero | S Nat first Cero _ = [] first (S n) (x:xs) = x:(first n xs)
Definición de funciones Ajuste de patrones Ejemplos: length [] = 0 length (x:xs) = 1+length xs data Nat = Cero | S Nat first Cero _ = [] first (S n) (x:xs) = x:(first n xs) Patrones Patrones
Definición de funciones Ajuste de patrones Una expresión e se ajusta a un patrón p (pattern matching) si e puede verse como una concreción de p (dando ciertos valores a las variables libres de p)
Definición de funciones Ajuste de patrones Ejemplo: la expresión S (S Cero) se ajusta al patrón S x pero no al patrón Cero S (S Cero) S (S Cero) X {x := S Cero} S x Cero
Definición de funciones Ajuste de patrones El ajuste de patrones permite clasificar datos y explorar / recuperar subestructuras de los mismos
Definición de funciones Distinción de casos Una función f se describe mediante ecuaciones de la forma: f p1 · · · pk = case x of q1 -> e1 ... qn -> en Donde p1 · · · pk, q1 · · · qn son patrones, x es una variable y e1 · · · en expresiones
Definición de funciones Distinción de casos Ejemplo: length xs = case xs of [ ] -> 0 (y:ys) -> 1+length ys
Definición de funciones Cláusulas where Una función f se describe mediante ecuaciones de la forma: f p1 · · · pk = e where l1 = r1 ... ln = rn Donde l1 · · · ln son patrones o partes izquierdas de definiciones de función, y r1 · · · rn son expresiones
Definición de funciones Cláusulas where Ejemplo: raicesEc2 a b c = ((-b+d)/a’,(-b-d)/a’) where d = sqrt(b^2-4*a*c) a’ = 2*a
Bibliografía Página WWW de Haskell: [Bir00] R. Bird. Introducción a la Programación Funcional con Haskell. Prentice-Hall, Madrid, 2000. [Dav92] A.J. Davie. An Introduction to Functional Programming Systems Using Haskell. Cambridge University Press, Cambridge, UK, 1992. [Pey03] S. Peyton Jones, editor. Haskell 98: Language and Libraries. The Revised Report. Cambridge University Press, 2003. Página WWW de Haskell: http://www.haskell.org
l : =