Programación funcional – Haskell

Tipos de datos simples
Booleanos
El tipo de datos Bool comprende valores que se corresponden con la declaración de tipos de datos:
data Bool = False | True deriving Show

esta declaración denomina Bool al tipo de datos, y True y False a sus 2 valores constituyentes, que extienden la clase Show que permite su visualización en pantalla. Una vez introducido Bool se pueden definir funciones que tomen argumentos booleanos, por ejemplo la función primitiva negación:
not :: Bool -> Bool not False = True not True = False

El lenguaje usa estas 2 ecuaciones como reglas de reescritura para simplificar expresiones de la forma not e. Primeramente, e se reduce a forma normal. Si este proceso termina y devuelve False, entonces se utiliza la primera ecuación; si la reducción devuelve True, entonces se usa la segunda ecuación. Si no se puede reducir e a forma normal, entonces el valor de not e es indefinido. Dos funciones básicas sobre los booleanos son las operaciones de conjunción, denotada por el operador binario &&, y disyunción, denotada por ||. Estas operaciones predefinidas admitirían la definición:
(&&),( || ) :: Bool -> Bool -> Bool False && x = False True && x = x (*Defina de manera análoga la operación disyunción*) 1 Hay 2 operadores de igualdad, == y /=. Se definen para argumentos booleanos (= =), (/=) :: Bool -> Bool -> Bool x = = y = (x && y) || (not x && not y) (*Defina /= basándose en = =*) 2 Ejercicios:

de este modo:

1. Defina la función bisiesto que determine si un año es bisiesto o no (un año es bisiesto si es divisible por
4, excepto si es divisible por 100, en cuyo caso debe ser también divisible por 400). 3

bisiesto

:: Integer -> Bool

bisiesto x = ………………………………………………………………………………. 2. La siguiente función triángulo toma 3 enteros positivos x, y, z (en orden no decreciente) que representan las longitudes de los lados de un posible triángulo (3 lados forman un triángulo si y sólo si la longitud del lado más largo es menor que la suma de las longitudes de los otros 2 lados), y determina si los 3 lados constituyen un triángulo y, de ser así, si el triángulo es escaleno (3 lados diferentes), isósceles (2 lados iguales) o equilátero (los 3 lados iguales). Así triangulo debe devolver 1 de 4 valores distintos. Se puede entonces definir: data Triangulo = Fallo | Isósceles | Equilátero | Escaleno triangulo :: (Integer, Integer, Integer) -> Triangulo triangulo (x, y, z) | x + y <= z = Fallo |x== z = Equilátero | (x = = y) || (y = = z) = Isósceles | otherwise = Escaleno
(*Defina una función Ordena3 que ordene 3 enteros en orden creciente. A partir de ella definir una función triangulo que no dependa de la suposición de que sus argumentos están en orden no decreciente*) 4

Caracteres
El tipo de datos predefinido Char contiene 256 caracteres, incluyendo tanto caracteres visibles como de control. Los caracteres se denotan encerrándolos entre símbolos de comillas simples. Son expresiones en forma canónica, por lo tanto el evaluador simplemente los muestra, incluyendo las comillas. Se proporcionan 2 funciones primitivas, ord y chr, para procesar caracteres. Sus tipos son: ord :: Char -> Int chr :: Int -> Char la función ord convierte un carácter c a un entero que lo representa en el rango 0 <= ord c < 255, y la función chr hace lo contrario, convertir un entero al carácter que representa. Se pueden definir funciones simples sobre caracteres, por ejemplo las siguientes que determinan si un carácter es un dígito, una letra minúscula o una letra minúscula: isDigit, isLower, isUpper :: Char -> Bool isDigit c = (‘0’ ≤ c) ^ (c ≤ ‘9’)
(*Defina de manera análoga la función isLower o isUpper*) 5 Ejercicios:

1

está declarada primero una clase de tipos Eq que consta de todos aquellos tipos para los cuales = = y ≠ están definidos: class Eq α where (= =). (≥ ) y (>). Defina una función aMayúscula que convierta minúsculas en mayúsculas. 8 Enumeraciones Un modo de definir un nuevo tipo de datos es enumerar explícitamente sus valores. Estas definiciones por defecto ahorran el trabajo de tener que repetirlas en cada declaración de concreción. y usar comparaciones entre enteros.(≤ ).Programación funcional – Haskell 3.(>) :: α -> α -> Bool (x ≤ y) = (x < y) ∨(x = = y) (x ≥ y) = (x > y) ∨(x = = y) (x > y) = not (x ≤ y) La primera línea dice que Ord es una subclase de Eq. siendo conveniente para ello codificarlos como enteros.(≥ ). Usando toEnum y fromEnum definir una función diaDespues que devuelva el día siguiente a un día dado. Por ejemplo: data Dia = Dom | Lun | Mar | Mie | Jue | Vie | Sab deriving (Eq. Los elementos del tipo Dia se pueden comparar. Definir una función valorNum que convierta un carácter dígito en su correspondiente valor numérico. por lo tanto. 6 4. Las 3 últimas líneas dan definiciones por defecto de las operaciones (≤ ). La declaración implícita es: class Enum a where toEnum :: Integer -> a fromEnum :: a -> Integer toEnum :: Integer -> Dia toEnum x |x==Dom = 0 |x==Lun = 1 |x==Mar = 2 |x==Mie = 3 |x==Jue = 4 |x==Vie = 5 |x==Sab = 6 instance Enum Char where toEnum = ord fromEnum = chr Se debe definir: En relación al tipo Char visto anteriormente. Enum. podemos declarar: instance Eq Dia where (x = = y) = (toEnum x = = toEnum y) instance Ord Dia where (x < y) = (toEnum x < toEnum y) Ejercicios: 6. y así sucesivamente se denominan constructoras del tipo de datos Dia. Por lo tanto es suficiente con dar la definición de (<) para cada concreción. se podría declarar: Los operadores de igualdad y desigualdad son sobrecargados. Suponer que la letra ‘A’ sigue a la ‘Z’. esto es que sólo puede dotarse con un orden a los tipos con igualdad. (≠ ) :: α → α → Bool Asimismo las operaciones de comparación están sobrecargadas. estando declarada otra clase de tipos Ord de este modo: class (Eq α) ⇒ Ord α where (<). Definir una función siguienteLetra que tome como argumento una letra del alfabeto y devuelva la letra que le sigue. Lun. definiéndose de modo diferente para distintos tipos de datos y. 9 7. que se consideran instancias de la clase de tipos Enum que describe tipos cuyos elementos pueden ser enumerados. 10 2 . 7 5. Dada la función toEnum de Dia. Ord. Show) Las 7 constantes Dom. Esto sucede con otros tipos enumerados. Definir un tipo de datos Direccion cuyos valores describan los puntos cardinales de la brújula y definir una función invertir para invertir una dirección.

5] = {notación} (1: (2 : [])) ++ (3 : (4 : (5 : [ ]))) = {segunda ecuación de ++} 1 : ((2 : ([]) ++ (3 : (4 : (5 : [ ]))) = {segunda ecuación de ++} 1 : (2 : ([] ++ (3 : (4 : (5 : [ ])))) = {primera ecuación de ++} 1 : (2 : (3 : (4 : (5 :[ ])))) = {notación} 3 . 4. 2] ++ [3. Por ejemplo. zs. y produce una tercera lista. Las listas se pueden usar para transportar datos de una función a otra. 3] ++ [4. 11 9. Se puede añadir elementos al principio de la lista o al final. Por ejemplo: [1. z. Y a las propias listas mediante xs. Podemos convenir en denotar elementos de listas con letras x. las listas de números se pueden sumar y multiplicar. Así. (*)] :: [Integer → Integer → Integer] Las cadenas son simplemente listas de caracteres escritas con una sintaxis especial. Por ejemplo: [1. 2. Toda operación genérica sobre listas es. 3] :: [Integer] [‘h’. y la construcción de listas se efectúa con el operador infijo ( : ). Cómo definiría la función head que devuelve el primer elemento de una lista no vacía. 5] [1. En la programación funcional. La segunda ecuación para ++ es muy sucinta y requiere alguna consideración. aplicable también a las cadenas. [3]] :: [[Integer]] [(+). [[]] es una lista unitaria cuyo único elemento es la lista vacía. 3. [1. Si todos los elementos de una lista tienen tipo α. también del mismo tipo. ‘l’. 2. En particular. ambas del mismo tipo. ¿Qué acción realiza dicha función? 15 init :: forall a. 3] = 1 : (2 : (3 : [])) = 1 : 2 : 3 : [] En otras palabras. una lista puede contener el mismo valor más de una vez. definida como se indica a continuación. ‘a’]. Escribir una función que genere de manera recursiva una lista conformada por los números del 1 a n. etc. comenzando con la lista vacía y añadiendo sucesivamente elementos uno por uno. La lista vacía se escribe [ ] y la lista unitaria. 2. “hola” es tan sólo una sintaxis adicional conveniente para la lista [‘h’. 2] la función predefinida init . se escribe [x]. se le asigna a la lista el tipo [α]. 12 10. la sintaxis especial de la izquierda puede verse como una abreviatura de la sintaxis de la derecha. ys. ‘o’. Escribir la función tail que devuelve el resto de la lista (excluyendo el primer elemento) 13 11. se ha comprendido gran parte de cómo funcionan las listas en la programación funcional. ‘o’. 2. 3] es una lista de 3 números y [“hola”. que contiene un solo elemento x. 4. 1]. ‘a’] :: [Char] [[1. las listas de caracteres se pueden leer e imprimir. Se puede construir una lista desde cero. 14 12. A diferencia de los conjuntos. por tanto. Por ejemplo: [1. Una lista finita se denota empleando corchetes y comas.[a] -> [a] init (x : xs) = if null xs then [ ] else x : init xs Operaciones sobre listas Concatenación Esta función se denota mediante el operador binario ++ (concatenar). la notación [] para la lista vacía. Escriba los pasos de evaluación que se verifican cuando se evalúa con la lista [1. y así sucesivamente. 2. y se usa la sintaxis [α] para designar las listas del tipo α. etc. De aquí la signatura de tipos. y. 5] La definición formal de ++ es: (++) :: [α] → [α] → [α] [ ] ++ ys = ys (x :xs) ++ ys = x : (xs ++ ys) La concatenación toma 2 listas. La función predefinida null comprueba si una lista está vacía: null :: [α] -> Bool null [] = True null (x : xs) = False La función predefinida last devuelve el último elemento de una lista no vacía: last (x : xs) = if null xs then x else last xs Ejercicios: 8. Por ejemplo: ? [1. Todos los elementos de una lista han de ser del mismo tipo. Por lo tanto: [1. Nótese que el número de pasos requeridos para calcular xs ++ ys es proporcional al número de elementos de xs. Si se comprende bien la definición de ++.Programación funcional – Haskell Listas El tipo de datos de las listas es la espina dorsal de la programación funcional. “adiós”] es una lista de 2 cadenas. Indicar la signatura de tipo para la función last. las listas son elementos de algún tipo α. 2]. ‘l’. o en algún punto intermedio.

. 32] ? filter odd [1. 4] !! 2 3 Esta operación es bastante costosa en la programación funcional. 3] [81.?. 10] es equivalente a invocar una función que devuelve la lista conformada por los números comprendidos entre 1 y 10 inclusive. 9] ? map (< 3) [1. devuelve la lista conformada por los números comprendidos entre ambos inclusive.” “. Indexación de listas drop :: Integer → [α] → [α] drop 0 xs = . 2] [] (*Completar las definiciones :*) 17 take :: Integer → [α] → [α] take 0 xs =[] take (n + 1) [ ] =[] take (n + 1) (x : xs) = . reverse [ ] =[] reverse (x : xs) = …………. la notación [1 . True. devuelven el primer elemento de una lista no vacía. 4.. Por ejemplo: ? filter even [1. El valor de take n xs es la lista constituida por los primeros n elementos de la lista xs y el de drop n xs es lo que queda de la lista. Por ejemplo: ?[1. Por ejemplo: ? take 3 “funcional” “fun” ? drop 3 “funcional” “cional” ? take 3 [1. Las funciones predefinidas take y drop toman cada una un entero no negativo n y una lista xs como argumentos. el resto de la lista tras quitar el primer elemento. 5] ? sum (map (^2) ( (filter even) [1. 32] [1. 2.. Longitud de una lista La longitud de una lista es el número de elementos que contiene: length :: forall a. Dicho en palabras. el último elemento de una lista no vacía. drop (n + 1) (x : xs) = drop n xs Para hallar el elemento que ocupa la posición n.?..[a] -> …. Definir la función upto que dados 2 enteros. Por ejemplo: ? map (^2) [9. 20 4 . 3. 18 14. 3. tail.[a] -> Integer length [ ] = 0 length (x : xs) = 1 + length xs Sublistas Las funciones predefinidas head. 4. 2. 32] [2. 3] [True. ya que necesita un número de pasos de reducción proporcional a n. Las funciones map y filter La función map aplica una función a cada elemento de una lista. 2. Por ejemplo: ? reverse “Dabale el abad. 4.. last e init.Programación funcional – Haskell [1. 2] ? drop 3 [1... 4.. 5] Inversión La función predefinida reverse invierte el orden de los elementos de una lista finita.?. 2.. 19 15. 5. 2. respectivamente.daba le elabaD” (*Completar la definición de reverse :*) 16 reverse :: forall a. para invertir una lista (x : xs) se invierte xs y luego se añade x al final. Esta operación se denota xs !! n. 5. se puede indexar una lista mediante un número natural n. Defina la función numérica sum que devuelve la suma de los componentes de una lista numérica. Defina la función booleana even que dado un entero devuelve True si el mismo es par. 2] [1. False] ? map siguienteLetra “HAL” “IBM” Su definición es: map :: (α -> β) -> [α] -> [β] map f [ ] =[] map f (x : xs) = f x : map f xs La función filter toma una función booleana f y una lista xs y devuelve la sublista de xs cuyos elementos satisfacen f. y la lista que queda tras eliminar el último elemento.10] )) 220 En el último ejemplo. Su definición es: filter :: (α → Bool) → [α] → [α] filter f [ ] =[] filter f (x : xs) = if f x then x : filter f xs else filter f xs Ejercicios: 13. drop (n + 1) [ ] = .

sólo renombra alguno existente (puede dar nombre a tuplas)..odd x] expresión generador guarda cualificador Un generador es de la forma x<-xs.. z) = (x^2 + y^2 = z^2) devuelve las ternas distintas de valores entre 1 y n devuelve True si la terna es pitagórica triadas :: Int -> [(Int.[1.n].β )->α ). max Char: ord (::Char->Int)(devuelve el valor ASCII de un caracter).2)]. zip (toma como argumentos 2 listas y devuelve la lista de los pares de elementos que se corresponden.2].1). Puede haber una secuencia de generadores y guardas.. z) | x <. Int) pitag :: (Int. z) <. Enumerados: data Nombre = valor1|valor2|… deriving (Enum. init (::[α ]->[α ]. Show).odd b] resultará en [(2. Int. reverse (:: [α ]->[α ]. Tipos Bool (valores True o False).β )->β ) ⇒ actúan sobre pares Enumeraciones: toEnum (::Int->α .3].1). unzip (toma una lista de pares y la separa en dos listas) Listas intensionales: notación alternativa para cálculos que necesitan map y filter. devuelve el primer elemento). snd (:: (α . drop (:: (Int. even (devuelve True si el argumento es par). ó -1 si no aparece 5 .[α ])->[α ].. sum (suma los elementos de la lista). invierte la lista).1). take (:: (Int.n] (devuelve la lista con los valores entre m y n inclusive) Funciones predefinidas Números: sqrt.[x. y. tail (::[α ]>[α ]. odd (devuelve True si el argumento es impar).. devuelve el último elemento). y. Expresiones Condicional: if condición then expresión_verdad else expresión_falsedad ecuaciones con guardas: |condición_1 = expresión_1 |condición_2 = expresión_2 … [ |otherwise = expresión_n] Operadores Aritméticos: + .[y. abs. constituye una ecuación. Ejemplos: triplas :: Int -> [(Int. max Tuplas: fst (:: (α . [m. aplica una función booleana f a una lista xs. devuelve la lista formada por los primeros n elementos de una lista xs). z) | (x. Ej: data Dia = Lun|Mar|Mié|Jue|Vie|Sáb|Dom deriving (Enum.y)<-zip[0.2]] daría como resultado [(1. Una guarda es una expresión booleana..] xs. devuelve la lista formada por los elementos que quedan después de eliminar los primeros n elementos de una lista xs).(2.y) = x*y posiciones :: Int->[Int]->[Int] posiciones x xs = [i|(i. devuelve el valor enumerado correspondiente al orden provisto). y. head (:: [α ]->α .Int)->α ). y. Int.Show) Listas: [tipo] ⇒ el tipo String corresponde a una lista de caracteres: [Char] Los valores constantes numéricos negativos se indican encerrándolos entre paréntesis (e incluyendo el signo). Nombre). Int) -> Bool triplas n = [(x. y devuelve la sublista de xs cuyos elementos satisfacen f). product (multiplica los elementos de la lista). devuelve lo que queda después de eliminar el último elemento). La lista [(a. Integer (valores numéricos enteros de rango arbitrario). last (:: [α ]->α . String (las constantes de este tipo se encierran entre comillas dobles).b<-[1.* / ^ div mod ⇒ deben usarse como funciones prefijas cuprificadas (por ej: mod 23 11 devuelve 1) (^2) ⇒ secciones (operadores con un argumento que actúan como funciones prefijas currificadas) Lógicos: == /= > >= < <= (de comparación) not && || Strings / Listas: ++ (concatenación).(1.triplas n. …) ⇒ pueden ser de diferentes tipos.b)|a<-[1. aplica una función a cada elemento de una lista). !! (indexación.1)]. Por ejemplo. z <. y. filter (:: (α ->Bool)->[α ]->[α ]. Int. donde x es una variable o tupla de variables y xs una lista..b<-[1. [(a. :: ([α ]. Float (hasta 7 dígitos decimales de precisión). Por ej: type Edad=Int type Nombre=String type Persona=(Edad. String) Renombramientos: type Nombre = tipo ⇒ no define un tipo nuevo. devuelve la longitud de la lista).(3. separados por comas.10]) en estilo combinatorio.Programación funcional – Haskell Resumen del lenguaje Funciones nombre_función :: Tipo_fuente -> Tipo_resultado ⇒ descripciones (signaturas) de tipo nombre_función (argumentos) = expresión ⇒ definición funcional (puede ser recursiva) [where nombre_local = expresión] ⇒ definición local nombre_función comienza con minúsculas. Por ejemplo: map (^2) (filter odd [1..10]. Tuplas: (tipo_valor1. fromEnum (::α ->Int) Listas: null (:: [α ]->Bool). maximum (devuelve el máximo de la lista). x==y] devuelve el producto escalar de los vectores xs e ys devuelve la lista de las posiciones en las que aparece el valor x dentro de la lista xs posición :: Int -> [Int] -> Int devuelve la posición en que aparece por primera vez el valor x posición x xs = head(posiciones x xs ++ [-1]) dentro de la lista xs.. y <.. map (:: (α ->β )->[α ]->[β ]. tipo_valor2.n]] pitag (x.[α ])->[α ]. min (función prefija currificada). Char (los valores constantes se encierran entre comillas simples). se expresa de manera intensional: [x^2|x<-[1. min.2).(2. devuelve lo que queda después de eliminar el primer elemento de una lista).(3. “Alvarez”) es del tipo (Int.n]. z)] pe :: [Int]->[Int]->Int pe xs ys = sum(map mult(zip xs ys)) where mult (x. minimum (devuelve el mínimo de la lista). Double (hasta 15 dígitos).3]. hasta donde pueda hacer corresponder). por ej. pitag (x. La parte de la definición “= expresión”. Int (valores numéricos enteros.2).b)|a<[1. (50. length (:: [α ]->Int. Int)] devuelve las ternas pitagóricas de valores entre 1 y n triadas n = [(x.. con hasta 10 cifras decimales en el rango -2 31 a 231-1). al igual que los nombres de variables correspondientes a argumentos.even a. chr (::Int->Char)(devuelve el carácter correspondiente a un valor ASCII).

isNaN. lex. flip. foldl1. shows. (**). readIO. cycle. Show. writeFile. ($). acos. isNegativeZero. sequence_.log. saín. splitAt. foldr. floatDigits. Concat. return. readLn IOError. getContents. words. Read. getLine. (. atan2 (RealFloat) subtract. span. unwords (String) ReadS. undefined. scanr1 (List) iterate. exponent. floatRange. floor (RealFrac) floatRadix. ioError. decodeFloat. foldr1. lcm. atanh (Floating) properFraction. scanl1.). (=<<) (Monad/Functor) id. Functor Funciones: curry (tuplas) uncurry ( “ ) maybe (Maybe) either (Either) succ. ShowS.Programación funcional – Haskell Tipos: Maybe Either Ordering Rational Clases: Eq Ord Enum Bounded Num Real Fractional Floating RealFrac RealFloat Monad. cos. interact FilePath. tan. elem. asTypeOf. takeWhile. putChar. (^^). isInfinite. isIEEE. exp. fmap. scanl. lookup (List) zip3. userError. ($!) (miscellaneous) foldl. fail. print. and. repeat. signum. tanh. enumFromThenTo (Enum) minBound. ceiling. pred (Enum) enumFrom. showParen (String convertion) String: putStr (:: String->IO( )) IO. gcd. until. readFile. (>>). or. replicate. concatMap. enumFromThen. atan. any. read. cosh. showChar. sinh. fromInteger (Num) toRational (Real) recip. notElem. truncate. zipWith3. fromIntegral. catch 6 . zipWith. realToFract (Num) (>>=). unlines. break. seq. scanr. isDenormalized. logBase. showString. fromRational (Fractional) pi. puStrLn. dropWhile. enumFromTo. readParen. mapM. significand (RealFloat) scaleFloat. const. sin. maxBound (Bounded) negate. putStr. encodeFloat. asin. unzip3 (List) lines. mapM_. all. acosh. error. getChar. sequence. reads. round. appendFile.

ya que a menudo la solución encontrada se podrá usar directamente o adaptar para el problema más complejo. t + 1) = convertir2 (t + 1) combinar3 (h + 1. dieciAlgo. “seiscientos”. “siete”. por ejemplo en un cheque. “setenta”. Integer) → String combinar3 (0. “ochenta”. “diecinueve”] veintiAlgo = [“veinte”. u + 1) = unidades !! u combinar2 (1. decenas :: [String] unidades = [“uno”. Integer) → String combinar2 (0. veintiAlgo. Tenemos entonces: convertir6 :: Integer → String convertir6 = combinar6 . y se quiere diseñar una función convertir de tal modo que el valor de convertir n sea la lista de caracteres que corresponde a la expresión en castellano del número n. Se puede en este caso definir: convertir2 :: Integer → String convertir2 = combinar2 . donde m es la parte de los millares y h es un número menor que mil. Por ejemplo. 0) = cientos !! h combinar3 (h + 1. “once”. t + 1) = cientos !! h ++ “⊔” ++ convertir2 (t + 1) Este paso es el más importante en el diseño del algoritmo completo. u + 1) = decenas !! t ++ “⊔y⊔” ++ unidades !! u El operador !! permite tomar de una lista el elemento que ocupa la posición n-ésima. “sesenta”. “ocho”. “veintidós”. digitos3 digitos3 :: Integer → (Integer. (x : xs) !! 0 = …. “quinientos”. (x : xs) !! (n + 1) = xs !! n Ampliemos ahora el rango a 0 < n < 1000. “quince”. por ejemplo 0 < n < 100. “cuatrocientos”. digitos2 digitos2 :: Integer → (Integer. debiendo aparecer una cantidad no sólo en cifras sino que también ha de ser escrita en letras. la función convertir6. Para ello definimos: convertir3 :: Integer → String convertir3 = combinar3 . “treinta”. Ahora ya podemos pasar a la siguiente y última etapa en la que n puede tener 6 dígitos y por lo tanto 0 < n < 1000000. “dieciocho”. “ochocientos”. Pueden darse como listas de cadenas: unidades. “veintiuno”. y después. “nueve”] dieciAlgo = [“diez”. “veinticuatro”. Supongamos entonces que el número n pertenece a un intervalo más pequeño. “veintisiete”. “doce”. “doscientos”. Integer) digitos3 n = (n div 100. 7 . “catorce”.. Supongamos que el número es un entero mayor que cero pero menor que un millón. “veinticinco”. “cuatro”. Completar la definición de !!: 21 (!!) :: [α] → Integer → …. en la definición de convertir2. “cincuenta”.Programación funcional – Haskell Ejemplo: convertir números en palabras A veces se necesita expresar números con letras. digitos6 (*Completar las definiciones de digitos6 y combinar6:*) 22 La función convertir requerida es. “setecientos”. u) = veintiAlgo !! u combinar2 (t + 3.. 9) Para definir combinar2 necesitamos nombres en castellano para los números más simples. “veintiocho”. por ejemplo: digitos2 9 = (0. n mod 10) Así será. “trescientos”. descomponemos t en la parte de las decenas y en otra parte menor que diez. “veintiséis”. 9) digitos2 99 = (9. “dieciséis”. Integer) digitos2 n = (n div 10. cuarenta”. precisamente. descomponemos n en dos números m y h.0) = decenas !! t combinar2 (t + 3. “veintitres”. “tres”. De forma similar al procedimiento anterior. trece”. Descomponemos n en dígitos en dos etapas: primero entre la parte de las centenas h y una parte t menor que cien. n mod 100) cientos = [“ciento”. deberá ser: ? convertir 369401 “trescientos sesenta y nueve mil cuatrocientos uno” Una buena manera de tratar problemas como éste es considerar primero un problema más simple. “veintinueve”] decenas = [“veinte”. “seis”. considerando la primera posición como 0. “cinco”. “noventa”] La definición de combinar2 emplea estas listas para extraer los elementos apropiados dependiendo de los dígitos: combinar2 :: (Integer. u) = dieciAlgo !! u combinar2 (2. “diecisiete”. “novecientos”] combinar3 :: (Integer. “dos.

Programación funcional – Haskell Notas al pie 8 .

Ord. z) = ordena1 ( ordena2 ( ordena1 (x. y. z) else (x.Enum. y) else (x.y.[a] -> a 12 head :: forall a. z) ordena2 :: (Int.1) 11 last :: forall a. y.Show) Invertir :: Direccion -> Direccion invertir x = if mod (fromEnum (x)) 2 == 0 then toEnum(fromEnum (x) + 1) else toEnum(fromEnum (x) . z) ordena3(x. z)) 5 isLower :: Char->Bool isLower c = (‘a’ <= c) && (c <= ‘z’) 6 aMayuscula :: Char -> Char aMayuscula c = if isLower c then chr (base + ord c) else c where base = ord ‘A’ – ord ‘a’ 7 siguienteLetra :: Char->Char siguienteLetra c = if c == ‘Z’ then ‘A’ else if c == ‘z’ then ‘a’ else chr (ord ( c ) + 1) 8 valorNum :: Char->Int valorNum c = ord (c ) – ord (‘0’) 9 diaDespues :: Dia->Dia diaDespues d = if d == Sab then Dom else toEnum (fromEnum ( d ) + 1) 10 data Direccion = Este | Oeste | Sur | Norte deriving (Eq.Int)->(Int.z))) ordena3 (x. y. y.Int.z)=ordena1(ordena2(ordena1(x.Int. z.Int.[a] → [a] reverse [ ]=[ ] reverse (x : xs) = reverse xs ++ [x] 17 take (n + 1) (x : xs) = x : take n xs drop 0 xs = xs drop (n + 1) [ ] = [ ] 18 even :: Integer → Bool even x = if x mod 2 == 0 then True else False 19 sum :: (Num α) ⇒ [α] → α sum [ ] =0 sum (x : xs) = x + sum xs 20 upto :: Integer → Integer → [Integer] upto m n = if m > n then [ ] else m : upto (m + 1) n 21 α x 22 digitos6 :: Integer → (Integer.y.1 False || x = x True || x = True 2 x ≠ y = not (x == y) 3 bisiesto x = if (mod x 100 == 0) then (mod x 400 == 0) else (mod x 4 == 0) 4 ordena1::(Int. y.[a] → [a] tail (x : xs) = xs 14 nros :: Integer -> [Integer] nros (n) = if n > 1 then nros (n – 1)++[n] else [n] 15 init [1.[a] -> a head (x : xs) = x 13 tail :: forall a. x.Int.Int) ordena2 (x. 2] = {notación} (1 : (2 : [ ] )) = {definición de init} (1 : init (2: [ ] )) = {definición de init} (1 : [ ] ) = {notación} [1] devuelve la lista que queda después de eliminar el último elemento 16 reverse :: forall a.Int)->(Int.Int. z) = if x > y then (y.Int) ordena1 (x. n mod 1000) . z))) triangulo2::(Int. z) = if y > z then (x. y. y.Int)->String triangulo2 = triangulo ( ordena3 (x. Integer) digitos6 n = (n div 1000.

h+1) = convertir3 (h+1) combinar6 (m+1.combinar6 :: (Integer. Integer) → String combinar6 (0. h+1) = convertir3 (m+1) ++ “⊔mil” ++ convertir3 (h+1) . 0) = convertir3 (m+1) ++ “⊔mil” combinar6 (m+1.