Tipos y estructuras de datos en los lenguajes funcionales Salvador Lucas Alba Departamento de Sistemas Informáticos y Computación Universidad Politécnica de Valencia http://www.dsic.upv.es/users/elp/slucas.html Objetivos • Introducir los tipos de datos como componente fundamental del estilo funcional • Introducir los mecanismos de estructuración y abstracción de datos en los lenguajes funcionales • Presentar los tipos y estructuras de datos usuales en los lenguajes funcionales Desarrollo 1. 2. 3. 4. Tipos Tipos básicos y tipos numéricos Tipos algebraicos Tipos funcionales: orden superior, definición de funciones 5. Listas y árboles 6. Tipos abstractos de datos Desarrollo 1. 2. 3. 4. Tipos Tipos básicos y tipos numéricos Tipos algebraicos Tipos funcionales: orden superior, definición de funciones 5. Listas y árboles 6. Tipos abstractos de datos Tipos Motivación • Evitar o detectar errores de programación Un tipo caracteriza el conjunto de valores que las expresiones de ese tipo pueden tener • Ayudar a estructurar la información Los tipos pueden verse como colecciones de valores que comparten ciertas propiedades • Ayudar a manejar estructuras de datos Los tipos indican cómo utilizar las estructuras de datos que comparten el mismo tipo Tipos Lenguajes tipificados • Un tipo representa el conjunto de valores que puede adoptar una variable o expresión • En los lenguajes tipificados, las variables adoptan un tipo (ej. Pascal, Haskell) • Los lenguajes que no restringen el rango de valores que pueden adoptar las variables son no tipificados (ej. Lisp, Prolog) Tipos Lenguajes tipificados En los lenguajes funcionales modernos todas las expresiones (y subexpresiones) tienen un tipo Tipos Lenguajes tipificados • Los lenguajes tipificados incorporan un sistema de tipos que determina si los programas son legales • Los sistemas de tipos se utilizan para determinar si los programas tienen un comportamiento adecuado Errores manifiestos 1/0 1/0 Errores ocultos Limites Limites vector vector Tipos Lenguajes tipificados • Un lenguaje de programación es seguro (safe) si no son posibles errores ocultos • Los lenguajes pueden garantizar la seguridad mediante comprobaciones estáticas (static check, ej. ML, Haskell), o dinámicas (dynamic check, ej. Lisp) Compilación Ejecución Tipos Lenguajes tipificados • En algunos lenguajes tipificados, la simple comprobación estática de tipos puede hacerlos seguros (ej. ML, Haskell) • En otros casos, esto no es así (ej. Pascal, C) Tipos Lenguajes tipificados El sistema de tipos de los lenguajes funcionales modernos garantiza la escritura de programas seguros Tipos Lenguajes tipificados • En los lenguajes con tipificación explícita, los tipos forman parte de la sintaxis • En los lenguajes con tipificación implícita, los tipos no forman parte de la sintaxis Lenguajes Expresiones Sistema de = + tipificados de programa tipos Tipos Lenguajes tipificados El sistema de tipos de los lenguajes funcionales modernos permite la tipificación implícita (debido a la posibilidad de inferencia de tipos) Sistemas de tipos Expresiones de tipo • Los tipos se describen mediante un lenguaje de expresiones de tipo: – – – – Tipos básicos o primitivos: Bool, Char, Int, ... Variables de tipo: a, b, c, ... Constructores de tipo: →, ×, [ ], ... Reglas de construcción de las expresiones: τ ::= Bool | Char | Int | ··· | t | τ → τ | τ × τ | [ τ ] | ··· Tipos Expresiones de tipo • Ejemplos: Tipos básicos • Bool, es el tipo de los valores booleanos True y Tipos False monomórficos • Int -> Int, es el tipo de la función fact, que devuelve el factorial de un número • [ a ] -> Int, es el tipo de la función length, que Tipos obtienen la longitud de una lista constituida por polimórficos elementos de cualquier tipo Variable de tipo Constructores de tipo Sistemas de tipos Asertos • Los sistemas de tipos permiten razonar sobre tipos y asociar expresiones de tipo con expresiones de programa: – Tipificación M :: τ – Equivalencia τ = τ’ τ<:τ’ – Subtipo (M tiene tipo τ) (τ y τ’ son equivalentes) (τ es un subtipo de τ’) Sistemas de tipos Sentencias • Las sentencias sobre las que se razona en los sistemas de tipos son de la forma: ⊥ Γ Φ Contexto de tipificación Aserto Γ= ∅, x1::τ1, x2::τ2, ..., xn::τn para n≥0 Con variables libres x1, x2, ..., xn Sistemas de tipos Sentencias • Ejemplo: True::Bool ⊥ ∅ x+1::Int ⊥ ∅, x::Int El tipo de True es Bool El tipo de x+1 es Int si el tipo de x es Int Sistemas de tipos Sistema formal • Las reglas del sistema de tipos tienen la forma general: (Nombre) Φ1 ... Γn ⊥ Γ ⊥ ⊥ Γ1 Φn (condiciones) Φ Sistemas de tipos Sistema formal • Ejemplo: (Env ∅) El contexto de tipificación vacío siempre es válido ◊ ⊥ ∅ Sistemas de tipos Sistema formal • Ejemplo (reglas de tipificación): (Val n) ⊥ Γ ◊ (n=0, ±1, ±2...) ⊥ Γ n::Int El tipo de un valor entero es Int en cualquier contexto de tipificación válido Sistemas de tipos Sistema formal • Ejemplo (reglas de tipificación): (Val +) N::Int M+N::Int ⊥ Γ Γ ⊥ M::Int ⊥ Γ Si las expresiones M y N son de tipo entero en Γ, también M+N lo es Tipos Lenguajes tipificados Un sistema de tipos es un conjunto de reglas de tipo Sistemas de tipos Sistema formal • Una derivación en un sistema de tipos es un árbol (invertido) de sentencias • Cada una se obtiene de las inmediatamente superiores por aplicación de una regla • Una sentencia válida es la que se puede obtener como raíz de una derivación Sistemas de tipos Sistema formal • Ejemplo: 1+2::Int ⊥ ∅ ∅ (por Env ∅) 2::Int (por Val n) ⊥ (por Val n) ◊ ⊥ ∅ (por Env ∅) 1::Int ⊥ ∅ ◊ ⊥ ∅ (por Val +) Sistemas de tipos Problemas de tipificación • Dos problemas fundamentales sobre tipificación de expresiones de programa: ⊥ – Comprobación de tipos (type checking): Dados M, Γ y τ, comprobar si Γ M :: τ es válida – Inferencia de tipos (type inference o type deduction): Dada M, obtener, en su caso, Γ y τ de forma que Γ M :: τ sea válida ⊥ Sistemas de tipos Problemas de tipificación • En ambos casos, es esencial disponer de algoritmos para realizar dichas tareas: – Algoritmo de comprobación de tipos (typechecking algorithm) – Algoritmo de inferencia de tipos (type inference algorithm) • La existencia y eficacia de éstos depende mucho del sistema de tipos Sistemas de tipos Problemas de tipificación Haskell utiliza el sistema de tipos (polimórficos) de Hindley-Milner que admite comprobación de tipos (Mycroft) e inferencia de tipos (Milner) Sistemas de tipos Problemas de tipificación • El sistema de tipos de Hindley-Milner tiene sus limitaciones: la función selfapplication f = f f no admite ningún tipo dentro de este sistema Sistemas de tipos Problemas de tipificación • Ejemplo: Dadas las ecuaciones fun f lista1 lista1 = f lista1 + f lista2 imposible = fun length [1,2,3] “abc” la expresión imposible no admite ningún tipo dentro de este sistema Sistemas de tipos Problemas de tipificación La elección de un sistema de tipos puede limitar la expresividad del lenguaje Sistemas de tipos Problemas de tipificación • Los algoritmos de comprobación de tipos (Mycroft) e inferencia de tipos (Milner) no son totalmente equivalentes Sistemas de tipos Problemas de tipificación • Ejemplo: consideremos la ecuación g x = 1:g (g ‘c’) El algoritmo de Milner falla al tratar de encontrar el tipo de g. Especificando g :: a -> [Int] el intérprete (que utiliza el algoritmo de Mycroft en ese caso) acepta la definición Sistemas de tipos Problemas de tipificación • Ejemplo: consideremos la ecuación gx=g1 El algoritmo de Milner infiere el tipo g :: Num a => a -> b mientras que el algoritmo de Mycroft acepta la tipificación explícita (más general) g :: a -> b Sistemas de tipos Problemas de tipificación A pesar de la posibilidad de tipificación implícita, a veces es recomendable dar los tipos de las funciones explícitamente Polimorfismo Polimorfismo paramétrico • Los tipos en cuya expresión de tipo no aparecen variables de tipo se denominan monotipos o tipos monomórficos • Los tipos en cuya expresión de tipo aparecen variables se denominan politipos o tipos polimórficos (polimorfismo paramétrico) • Un tipo polimórfico representa un número infinito de monotipos Polimorfismo Polimorfismo paramétrico • Ejemplo: la función length :: [a] -> Int puede verse como una función con infinitos monotipos [Int] -> Int, [Bool] -> Int, [Int -> Int] -> Int, ... Polimorfismo Polimorfismo paramétrico • Ejemplo: La implementación de length :: [a] -> Int es única: length [ ] =0 length (x:xs) = 1+length xs y resulta válida para todos los usos de la función Polimorfismo Polimorfismo paramétrico • Con un sistema de tipos polimórficos, el algoritmo de inferencia de tipos intenta obtener el tipo principal de las expresiones • El tipo principal es el tipo más general capaz de capturar todos los usos válidos de la expresión Polimorfismo Polimorfismo paramétrico El sistema de tipos de Hindley-Milner asegura que toda expresión tipificable tiene un tipo principal único Polimorfismo Sobrecarga • A veces nos interesa sobrecargar el uso de ciertos operadores, aplicándolos sobre argumentos de distintos tipos, aunque de forma limitada • Otras veces, no tiene sentido asignar un politipo a un operador si no podemos implementar todas sus concreciones Polimorfismo Sobrecarga • Este tipo de polimorfismo se denomina polimorfismo ad-hoc o sobrecarga (overloading) Polimorfismo Sobrecarga • Ejemplo: los operadores aritméticos (+), (-), (*), (/), ..., suelen estar sobrecargados: (+) :: Int -> Int -> Int (+) :: Float -> Float -> Float (+) :: Complex -> Complex -> Complex corresponden a distintos usos de (+). Otro: (+) :: Int -> Float -> Float Polimorfismo Sobrecarga • El operador (+) no puede recibir el politipo (+) :: a -> a -> a porque implicaría dotar de significado a la ‘suma’ de caracteres, funciones, listas, etc., lo cual puede interesarnos o no Polimorfismo Sobrecarga • Ejemplo: El operador de igualdad (==), aun teniendo una semántica bien definida, no es implementable en algunos casos. ¿Cómo determinar (efectivamente) si dos funciones son iguales? Polimorfismo Sobrecarga • Matemáticamente: sean f:D→E y g:D→E dos funciones. Tenemos que f =D → E g si y sólo si ∀x∈D, f(x) =E f(x) Si D es infinito, o f no es computable, =D → E puede no ser decidible Polimorfismo Sobrecarga • El operador (==) no puede recibir el politipo (==) :: a -> a -> Bool porque tendríamos que implementar la comprobación de igualdad para todos los tipos; en particular para las funciones: (==) :: (a->b) -> (a->b) -> Bool Polimorfismo Sobrecarga En Haskell, el polimorfismo ad-hoc se implementa mediante el concepto de clase Polimorfismo Sobrecarga • Una clase es una colección de tipos • Todos los tipos pertenecientes a una clase deben tener definidas ciertas operaciones Polimorfismo Sobrecarga • Ejemplo: – Los miembros de la clase Eq deben definir las operaciones (==) y (/=) para comprobar si dos elementos son iguales o distintos – Los miembros de la clase Ord deben tener definidas, además de (==) y (/=), las relaciones (<) y (<=) para comparar elementos entre sí Polimorfismo Sobrecarga class Eq a where -- simplificado (==), (/=) :: a -> a -> Bool class Eq a => Ord a where -- simplificado (<), (<=), (>), (>=) :: a -> a -> Bool Ord es una subclase de Eq Polimorfismo Sobrecarga • De acuerdo con la declaración anterior, el tipo (sobrecargado) de (==) es (==) :: Eq a => a -> a -> Bool que se interpreta como sigue: si a es un tipo de la clase Eq, el tipo de (==) es a -> a -> Bool Polimorfismo Sobrecarga • Algunas clases predefinidas de Haskell son: Eq: tipos con comprobación de igualdad Ord: tipos con operadores de comparación Enum: tipos cuyos valores son secuenciables Show: tipos cuyos valores son convertibles en cadenas de caracteres – Num, Integral, Fractional, Real, Floating, RealFrac, RealFloat: clases numéricas – – – – Polimorfismo Sobrecarga • Es posible añadir nuevos tipos a una clase, si particularizamos las operaciones propias de ésta para los valores del nuevo tipo Polimorfismo Sobrecarga • Ejemplo: consideremos el tipo data Nat = Cero | S Nat deriving Show Podemos añadirlo a la clase Eq: instance Eq Nat where Cero== Cero = True S n == S m = m == n _ == _ = False Polimorfismo Sobrecarga • Ejemplo: En realidad, bastaría con escribir data Nat = Cero | S Nat deriving (Eq, Show) Polimorfismo Sobrecarga • La clase Num se define como class (Eq a, Show a) => Num a where (+),(-),(*) :: a -> a -> a ¡¡Simplificado!! Polimorfismo Sobrecarga • Podemos añadir el tipo Nat a la clase Num: instance Num Nat where No es preciso Cero + n = n definir todas (S n) + m = S (n+m) las operaciones Cero * n = Cero (¡¡pero no se podrán usar!!) (S n) * m = m + (n*m) Polimorfismo Sobrecarga • Ahora podríamos escribir, directamente: fact Cero = S Cero fact (S n) = (S n) * fact n ¡¡Sobrecargado!! Desarrollo 1. 2. 3. 4. Tipos Tipos básicos y tipos numéricos Tipos algebraicos Tipos funcionales: orden superior, definición de funciones 5. Listas y árboles 6. Tipos abstractos de datos Tipos básicos • Los tipos básicos proporcionados por Haskell son: – – – – – Booleanos Caracteres Tuplas Cadenas Tipos numéricos Tipos básicos Booleanos • • Los valores del tipo Bool son True y False El tipo Bool pertenece a las clases Bounded, Enum, Eq, Ord y Show, entre otras Tipos básicos Booleanos • El perfil de la clase Enum es: class Enum a where succ,pred :: a -> a toEnum :: Int -> a fromEnum :: a -> Int ¡¡Simplificado!! Tipos básicos Booleanos • Operaciones usuales para Bool (en Haskell): – Conjunción:&& :: Bool -> Bool -> Bool – Disyunción:| | :: Bool -> Bool -> Bool – Negación: not :: Bool -> Bool Tipos básicos Caracteres • Los valores del tipo Char son los caracteres: – – – – – – ‘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’, ... Tipos básicos Caracteres • • El tipo Char pertenece a Bounded, Enum, Eq, Ord y Show Operaciones usuales para Char: – isAlpha, isAlphaNum, isAscii, isDigit, isLower, isPrint, isUpper :: Char -> Bool – toLower, toUpper :: Char -> Char – chr :: Int -> Char -- toEnum – ord :: Char -> Int -- fromEnum Tipos básicos Tuplas • El tipo polimórfico (a,b) (en general, (a1,..., an) ) permite agrupar valores procedentes de tipos distintos: (True,False) :: (Bool,Bool) (True,’a’) :: (Bool,Char) ((True,False),’a’) :: ((Bool,Bool),Char) (isDigit,’a’,1) :: (Char -> Bool, Char,Int) Tipos básicos Tuplas • • El tipo tupla pertenece a las clases Eq, Ord, Show y Enum, entre otras Operaciones usuales sobre tuplas: – Proyección izq: – Proyección der: fst :: (a,b) -> a snd :: (a,b) -> b ¡¡Sólo con pares!! Tipos básicos Cadenas • • Los valores del tipo String son las cadenas de caracteres: “”, “1&bA”, “Esta frase \10ocupa dos lineas” En realidad, String es un tipo sinónimo: type String = [Char] Tipos básicos Cadenas • El tipo String pertenece a las clases Eq, Ord y Show, entre otras Tipos numéricos Números en Haskell • Los tipos numéricos en Haskell son: – – – – Int, Integer: Números enteros Float, Double: Números reales Ratio: Números racionales Complex: Números complejos Preludio Estándar Librerías Tipos numéricos Números enteros • Los valores del tipo Int son los enteros de rango acotado: 0, 45, -3452, 2147493647 • • El límite es maxBound :: Int El tipo Int pertenece a la clase Bounded class Bounded a where minBound :: a maxBound :: a Tipos numéricos Números enteros • El tipo Int también pertenece a las clases Enum, Eq, Ord y Show, además de a las clases numéricas Num, Real e Integral Tipos numéricos Números enteros class (Eq a, Show a) => Num a where (+),(-),(*) :: a -> a -> a negate :: a -> a abs,signum :: a -> a fromInteger :: Integer -> a Tipos numéricos Números enteros class (Num a, Ord a) => Real a where toRational :: a -> Rational class (Real a, Enum a) => Integral a where quot,rem,div,mod :: a -> a -> a quotRem, divMod :: a -> a -> (a,a) toInteger :: a -> Integer Tipos numéricos Números enteros • • Los valores del tipo Integer son los enteros de rango arbitrario La aritmética con Integer es más precisa que con Int, pero más costosa Tipos numéricos Números enteros • El tipo Integer pertenece a las clases Enum, Eq, Ord y Show (pero no a Bounded), además de a las clases numéricas Num, Real e Integral Tipos numéricos Números reales • Los valores del tipo Float son los números en coma flotante de precisión simple: 0.31426, -23.12, 567.347, 4523.0 231.61e7, 231.6e-2, -3.412e03 Tipos numéricos Números reales • El tipo Float pertenece a las clases Enum, Eq, Ord y Show (no a Bounded), además de a las clases numéricas Num, Real, Fractional, Floating, RealFrac y RealFloat Tipos numéricos Números reales class (Num a) => Fractional a where (/) :: a -> a -> a recip :: a -> a fromRational :: Rational -> a Tipos numéricos Números reales class (Fractional a) => Floating a where pi :: a exp,log,sqrt :: a -> a (**),logBase :: a -> a -> a sin,cos,tan, asin,acos,atan, sinh,cosh,tanh, asinh,acosh,atanh :: a -> a Tipos numéricos Números reales class (Real a,Fractional a) => RealFrac a where properFraction :: (Integral b) => a -> (b,a) truncate,round :: (Integral b) => a -> b ceiling,floor :: (Integral b) => a -> b Tipos numéricos Números reales class (RealFrac a,Floating a) => RealFloat a where floatRadix :: a -> Integer floatDigits :: a -> Int floatRange :: a -> (Int,Int) decodeFloat :: a -> (Integer,Int) encodeFloat :: Integer -> Int -> a Tipos numéricos Números reales class (RealFrac a,Floating a) => RealFloat a where -- Continuación exponent :: a -> Int significand :: a -> a scaleFloat :: Int -> a -> a isNaN,isInfinite:: a -> Bool isDenormalized:: a -> Bool isIEEE :: a -> Bool Tipos numéricos Números reales Otras operaciones de interés son: (^) :: (Integral b, Num a) => a -> b -> a Potencia con exponente entero (^^) :: (Integral b, Fractional a) => a -> b -> a Potencia con exponente racional Tipos numéricos Números reales • • Los valores del tipo Double son los números en coma flotante de precisión doble El tipo Double pertenece a las mismas clases que Float Tipos numéricos Números racionales y complejos • • • Los tipos Ratio y Rational, para trabajar con números racionales, se definen en la librería Ratio de Haskell 98 El tipo Complex, para trabajar con números complejos, se definen en la librería Complex de Haskell 98 La librería Numeric de Haskell 98 describe funciones numéricas adicionales Tipos numéricos Num Int,Integer,Float,Double Real Fractional Int,Integer,Float,Double Float,Double Integral RealFrac Floating Int,Integer Float,Double Float,Double RealFloat Float,Double Desarrollo 1. 2. 3. 4. Tipos Tipos básicos y tipos numéricos Tipos algebraicos Tipos funcionales: orden superior, definición de funciones 5. Listas y árboles 6. Tipos abstractos de datos Tipos Tipos algebraicos • Los tipos algebraicos 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 Tipos algebraicos • Los tipos algebraicos 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) Constructores de tipos Tipos Tipos algebraicos • Los tipos algebraicos se definen junto con los valores que éstos contienen • Ejemplos: • Simples • • Estructurados • 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 datos Tipos Tipos algebraicos • Los tipos algebraicos 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) Polimórfico Variables de tipo Tipos Tipos algebraicos • 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 Tipos algebraicos • 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 Tipos algebraicos • Ejemplo de valor del tipo TreeInt 1 4 2 3 (B (L 1) (B (B (L 2) (L 3)) (L 4))) Tipos Tipos algebraicos • 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) Desarrollo 1. 2. 3. 4. Tipos Tipos básicos y tipos numéricos Tipos algebraicos Tipos funcionales: orden superior, definición de funciones 5. Listas y árboles 6. Tipos abstractos de datos Tipos funcionales • Los tipos funcionales (que involucran el constructor de tipo →) son muy importantes en programación funcional • Ejemplo: Int -> Int a -> Bool Num a => a -> a -> a (a -> b) -> [a] -> [b] Tipos funcionales Valores funcionales • Los valores funcionales pueden especificarse de dos formas: – explícitamente: mediante expresiones lambda – implícitamente: mediante ecuaciones Definición de funciones 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 Definición de funciones Expresiones lambda • Ejemplo \ x y -> x+y \ x -> 2*x \ x -> True \ m n -> B (L m) (L n) Definición de funciones Expresiones lambda La definición de funciones recursivas es problemática (¡aunque no imposible!) Definición de funciones Ecuaciones • 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 triple x seisveces x fact n = x+x = 3*x = doble (triple x) = 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) = if n==0 then 1 else fact n 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 | | sign x | | | n==0 = 1 n>0 = n*fact (n-1) x<0 = neg x==0 = cero x>0 = pos Definición de funciones Parámetros formales y guardas • Ejemplos: fact n | | sign x | | | n==0 = 1 n>0 = n*fact (n-1) 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) {x := S Cero} Sx S (S Cero) 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 Orden superior Funciones como ciudadanos de primera clase • En programación funcional, las funciones son ‘ciudadanos de primera clase’ (first class citizens): Orden superior Funciones como ciudadanos de primera clase • En programación funcional, las funciones son ‘ciudadanos de primera clase’ (first class citizens): – Pueden ser pasadas, como argumentos, a otras funciones Orden superior Funciones como ciudadanos de primera clase • En programación funcional, las funciones son ‘ciudadanos de primera clase’ (first class citizens): – Pueden ser pasadas, como argumentos, a otras funciones – Pueden ser devueltas como resultado de una llamada a función Orden superior Funciones como ciudadanos de primera clase map aplica una función f • Ejemplos: a cada elemento de una lista map f [] = [] map f (x:xs) = (f x):map f xs add x y add2 = x+y = add 2 aplicación parcial add2 añade 2 al número que se le pasa como argumento Orden superior Currificación • A cada función (sobre k-tuplas) f: D1 × D2 × ··· × Dk → E le corresponde una función fC: D1 → (D2 → ( ··· → (Dk → E)···) que a cada valor de D1 le asocia una función de k-1 argumentos (y viceversa) • fC es la versión currificada de f Orden superior Currificación • Ejemplo: map :: (a -> b) -> [a] -> [b] if :: Bool -> a -> a -> a + :: Num a => a -> a -> a Orden superior Currificación • El operador -> es asociativo por la derecha a -> b -> c a -> (b -> c) equivale a y difiere de (a -> b) -> c • El operador de aplicación (a veces denotado como @) es asociativo por la izquierda f ab equivale a (f a) b y difiere de f (a b) Orden superior Currificación • En programación funcional ésto facilita la aplicación parcial de una función: si f :: a -> b -> c Entonces, si e::a, escribir fe tiene sentido pleno: se trata de una función f e :: b -> c Orden superior Currificación • Ejemplo: la expresión map add2 [1,2] es válida en un lenguaje como Haskell, y sería equivalente a map (add 2) [1,2] o incluso Sección map (+ 2) [1,2] Desarrollo 1. 2. 3. 4. Tipos Tipos básicos y tipos numéricos Tipos algebraicos Tipos funcionales: orden superior, definición de funciones 5. Listas y árboles 6. Tipos abstractos de datos Bibliografía [Car97] L. Cardelli. Type Systems. [PE93] R. Plasmeijer and M. van Eekelen. Functional Programming and Parallel Graph Rewriting. AddisonWesley, Reading, MA, 1993 [Rea93] C. Reade. Elements of Functional Programming. Addison-Wesley, Reading, MA, 1993 λ :=