Introducción a la Programación Genérica Alberto Pardo Instituto de Computación Facultad de Ingeniería Universidad de la República http://www.fing.edu.uy/inco/cursos/proggen Objetivo del curso Introducción de conceptos y técnicas avanzadas en el contexto de programación funcional. Temas principales: Programación genérica. Mecanismos para definir funciones por inducción en la estructura de los tipos que manipulan. Razonamiento algebraico. Propiedades algebraicas entre programas útiles para la derivación y transformación de programas. Fusión de programas. Técnica de transformación de programas para la eliminación de estructuras de datos intermedias generadas en las composiciones de funciones. Nuestro abordaje a estos temas será estructural. Prog. Genérica - InCo 1
Funciones Genéricas Polimorfismo paramétrico Las funciones polimórficas trabajan exactamente de la misma manera sobre todas las instancias del tipo polimórfico. length :: [a] -> Int length [] = 0 length (x:xs) = 1 + length xs concat :: [[a]] -> [a] concat [] = [] concat (x:xs) = x ++ concat xs Prog. Genérica - InCo 3
Polimorfismo ad-hoc (sobrecarga) En Haskell, la sobrecarga es manejada mediante type classes. class (Eq a, Show a) => Num a where (+) :: a -> a -> a... Las instancias de una clase son definidas separadamente y pueden contener algoritmos completamente diferentes. instance Num Int where (+) =... instance Num Float where (+) =... Prog. Genérica - InCo 4 Polimorfismo ad-hoc: data compression Codificación de elementos de cualquier tipo como cadenas de bits. data Bit = 0 1 class Encode a where encode :: a -> [Bit] instance Encode Int where encode = encodeint -- cantidad fija de bits instance Encode Char where encode = encodechar -- cantidad fija de bits instance Encode a => Encode [a] where encode [] = [0] encode (a:as) = 1 : encode a ++ encode as Prog. Genérica - InCo 5
Polimorfismo genérico Funciones que funcionan esencialmente de la misma forma sobre tipos diferentes. sumlist :: [Int] -> Int sumlist [] = 0 sumlist (n:ns) = n + sumlist ns data IntTree = Empty Node IntTree Int IntTree sumtree :: IntTree -> Int sumtree Empty = 0 sumtree (Node l n r) = n + sumtree l + sumtree r La idea es definir una funcón sum :: t -> Int que capture todas las instancias. Prog. Genérica - InCo 6 Polimorfimso genérico No es posible definir una función polimórfica para la igualdad. equal :: a -> a -> Bool Debido a una propiedad de parametricidad una función con este tipo debe ser constante (ya que los argumentos en las posiciones polimórficas no pueden ser inspeccionados). Estamos forzados entonces a escribir una función de igualdad para cada tipo. equal :: (Eq a) => a -> a -> Bool Programación genérica permite definir una función de igualdad que trabaja en forma uniforme para todos los tipos. Prog. Genérica - InCo 7
Type-indexed functions Son funciones definidas por inducción en la estructura de los tipos. f<t> ::...t... Prog. Genérica - InCo 8 Type-indexed functions: data compression Consideremos por un momento la familia de tipos de esta forma: τ ::= Int enteros Char caracteres (τ, τ) pares [τ] listas Deseamos definir una función encode<t> :: t -> [Bit] que se pueda aplicar sobre todos los tipos t de la familia. Prog. Genérica - InCo 9
Type-indexed functions: data compression encode<t> :: t -> [Bit] encode<int> i = encodeint i encode<char> c = encodechar c encode<(ta,tb)> (a,b) = encode<ta> a ++ encode<tb> b encode<[ta]> [] = [0] encode<[ta]> (a:as) = 1 : encode<ta> a ++ encode<[ta]> as donde encodeint :: Int -> [Bit] encodechar :: Char -> [Bit] Prog. Genérica - InCo 10 Type-indexed functions: data compression decode<t> :: [Bit] -> (t,[bit]) decode<int> bs = decodeint i decode<char> bs = decodechar c decode<(ta,tb)> bs = let (a,bs ) = decode<ta> bs (b,bs ) = decode<tb> bs in ((a,b),bs ) decode<[ta]> [] = error decode decode<[ta]> (0:bs) = ([],bs) decode<[ta]> (1:bs) = let (a,bs ) = decode<ta> bs (as,bs ) = decode<[ta]> bs in (a:as,bs ) donde decodeint :: [Bit] -> (Int,[Bit]) decodechar :: [Bit] -> (Char,[Bit]) Prog. Genérica - InCo 11
Ejemplos de funciones genéricas Parsers Pretty printers (show) Compactadores/descompactadores Recorridas sobre estructuras de datos (traversals) Funciones de igualdad y de comparación Zip/unzip de estructuras Aplicaciones en XML Prog. Genérica - InCo 12 Fusión de programas
Ejemplo: count count :: Word -> Text -> Integer count w = length. filter (==w). words words :: Text -> [Words] words t = case dropwhile isspace t of "" -> [] t -> let (w,t ) = break isspace t in w : words t filter :: (a -> Bool) -> [a] -> [a] filter p [] = [] filter p (a:as) = if p a then a : filter p as else filter p as Prog. Genérica - InCo 14 Fusión count w = length. filter (==w). words count w t = case dropwhile isspace t of "" -> 0 t -> let (w,t ) = break isspace t in if w = = w then 1 + count w t else count w t Prog. Genérica - InCo 15
Cronograma del curso Cronograma 1. Inducción/Recursión estructural 2. Conceptos preliminares 3. Modelado algebraico de tipos de datos 4. Los operadores fold y map 5. Funciones politípicas 6. Lenguajes de programación genérica (PolyP, Generic Haskell) 7. Otros abordajes a programación genérica Prog. Genérica - InCo 17