introalg:taller08_4
Diferencias
Muestra las diferencias entre dos versiones de la página.
Ambos lados, revisión anteriorRevisión previaPróxima revisión | Revisión previa | ||
introalg:taller08_4 [2008/05/10 20:50] – laura | introalg:taller08_4 [2018/08/10 03:03] (actual) – editor externo 127.0.0.1 | ||
---|---|---|---|
Línea 75: | Línea 75: | ||
[False, | [False, | ||
- | === Ejercicio === | ||
- | * Utilizando aplicación parcial en //( /= )//, definir la función //noEsCero :: Int -> Bool// que decide si un entero //x// es distinto a 0. | + | ===== Generalización de las funciones vistas (map, filter, fold) ===== |
- | + | ==== Aplicaciones | |
- | ===== Generalización de las funciones vistas | + | |
- | + | ||
- | ==== Aplicaciones | + | |
¿No estamos ya cansados de escribir siempre lo mismo? | ¿No estamos ya cansados de escribir siempre lo mismo? | ||
Línea 128: | Línea 124: | ||
rangoEdades (x:xs) = rangoEdad x : rangoEdades xs | rangoEdades (x:xs) = rangoEdad x : rangoEdades xs | ||
- | | + | ___________ |
- | [] = [] | + | |
- | (x:xs) = | + | |
Si queremos hacer esta expresión independiente de tipos, usaremos los comodines de tipo //a//, //b//, etc. en lugar de los tipos comunes //Int//, //String//, etc. | Si queremos hacer esta expresión independiente de tipos, usaremos los comodines de tipo //a//, //b//, etc. en lugar de los tipos comunes //Int//, //String//, etc. | ||
- | | + | ___________ |
- | [] = [] | + | |
- | (x:xs) = | + | |
A esta base común hay que añadir un argumento más: la función que se aplicará a todos los elementos de la lista. En el ejemplo anterior, la función era // | A esta base común hay que añadir un argumento más: la función que se aplicará a todos los elementos de la lista. En el ejemplo anterior, la función era // | ||
- | | + | |
- | | + | |
- | | + | |
De esta forma, llamando a la función general con diferentes operaciones como argumento, podremos definir las diferentes funciones que hemos visto hasta ahora, por ejemplo: | De esta forma, llamando a la función general con diferentes operaciones como argumento, podremos definir las diferentes funciones que hemos visto hasta ahora, por ejemplo: | ||
- | duplica | + | duplicar |
+ | cuadrados xs = aplicar (^2) xs | ||
+ | rangoEdades xs = aplicar rangoEdad | ||
O bien aplicando secciones, es decir, sin escribir los argumentos obvios: | O bien aplicando secciones, es decir, sin escribir los argumentos obvios: | ||
- | duplica | + | duplicar |
+ | cuadrados = aplicar (^2) | ||
+ | rangoEdades = aplicar rangoEdad | ||
- | === Ejercicio | + | ==== Filtros |
- | + | ||
- | * Definir la función // | + | |
- | + | ||
- | probar con mapNumeros.(*2).[0, | + | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | ==== Filtros | + | |
Veamos funciones de //tipo filtro// que hemos creado: | Veamos funciones de //tipo filtro// que hemos creado: | ||
Línea 187: | Línea 178: | ||
</ | </ | ||
- | Entonces plantemos el mismo tipo de ejercicio, una generalización que tome como primer parámetro un **predicado**, | + | ¿Cuál |
- | === Ejercicio === | + | __________ :: [Int] -> [Int] |
+ | __________ [] = [] | ||
+ | __________ (x:xs) | ______ x | ||
+ | | otherwise | ||
- | * Definir la función // | ||
- | probar con filtraNumeros.entre0y9.[], filtraNumeros.entre0y9.[10,20,30]. | + | Si queremos hacer esta expresión independiente de tipos, usaremos los comodines de tipo a, b, etc. en lugar de los tipos comunes Int, String, etc. |
+ | __________ :: [a] -> [a] | ||
+ | __________ [] = [] | ||
+ | __________ (x:xs) | ______ x = x : _____________ xs | ||
+ | | otherwise = _____________ xs | ||
+ | A esta base común hay que añadir un argumento más: la función que se va a evaluar para todos los elementos de la lista. Este tipo de función es un **predicado**, | ||
+ | filtrar :: (a -> Bool) -> [a] -> [a] | ||
+ | filtrar p [] = [] | ||
+ | filtrar p (x:xs) | p x = x : filtrar p xs | ||
+ | | otherwise = | ||
+ | |||
+ | De esta forma, llamando a la función general con diferentes operaciones como argumento, podremos definir las diferentes funciones que hemos visto hasta ahora, por ejemplo: | ||
+ | |||
+ | soloPares xs = filtrar esPar xs | ||
+ | empiezaM xs = filtrar primeraEsM xs | ||
+ | |||
+ | O bien aplicando secciones, es decir, sin escribir los argumentos obvios: | ||
+ | |||
+ | soloPares = filtrar esPar | ||
+ | empiezaM = filtrar primeraEsM | ||
+ | |||
+ | |||
+ | Observemos que en el caso de los filtros, los elementos de la lista resultado tienen que ser del mismo tipo que los elementos de la lista que damos como argumento (//[a] -> [a]//), ya que la función filtro **no modifica** los elementos, sino que solamente determina si deben o no deben formar parte del resultado. En cambio, en las aplicaciones el resultado puede ser de distinto tipo que el argumento (//[a] -> [b]//), porque la aplicación sí puede modificar los elementos de la lista de entrada, incluso cambiándolos de tipo. Notemos que //[a] -> [b]// significa que **podemos** encontrar tipos distintos (como en // | ||
- | ==== Acumuladores ==== | + | ==== Acumuladores |
Más y más funciones fueron acumuladores, | Más y más funciones fueron acumuladores, | ||
Línea 218: | Línea 233: | ||
productoria (x:xs) = producto x (productoria xs) | productoria (x:xs) = producto x (productoria xs) | ||
</ | </ | ||
- | |||
< | < | ||
Línea 226: | Línea 240: | ||
</ | </ | ||
- | === Ejercicio === | + | ¿Cuál es la estructura común de todas estas funciones? Para poder verla bien, debemos saber que todo operador que usemos entre sus dos argumentos, como //+//, //:// o //++//, se puede usar también con la misma sintaxis que cualquier otra función, es decir, delante de sus dos argumentos. Para ello hay que poner al operador entre paréntesis, |
- | Definir la primera generalización. | + | sumatoria (x:xs) = (+) x (sumatoria xs) |
- | * Definir la función | + | Donde el primer número a sumar es //x// y el segundo es //sumatoria xs//, es decir, el resultado |
- | probar con paraTodoInt.multiplo2.[2,3,4], paraTodoInt.entre0y9.[1, | + | Entonces, la estructura común de todas estas funciones es: |
- | Y luego esta que es casi completa. | + | _________ :: [a] -> b |
+ | _________ [] = _____ | ||
+ | _________ (x:xs) = _____ x (_________ xs) | ||
- | * Definir la función // | ||
- | probar con acumulaInt.(+).0.[1,2,3], acumulaInt.(*).1.[1,2,3]. | + | Como el resultado de la función no es una lista, el resultado del caso base no es una lista vacía. El resultado del caso base debe ser definido para cada función, ya que debe ser el neutro del operador que se utilice en la función. Por lo tanto, en los acumuladores tendremos un argumento más que en las aplicaciones y los filtros, justamente, el neutro. |
- | ===== Escribamos las versiones más generales ===== | + | Por lo tanto, la generalización de los acumuladores es la siguiente: |
- | Hasta ahora trabajamos con las generalizaciones de las funciones desde el punto de vista que le podíamos dar cualquier función para que operara sobre los valores. | + | acumular :: (a -> b -> b) -> b -> [a] -> b |
- | Es posible generalizar estas funciones | + | acumular f n [] = n |
+ | acumular f n (x:xs) = f x (acumular f n xs) | ||
- | ==== Aplicaciones (map) ==== | + | Ahora podemos escribir todas las funciones que son acumuladores mediante esta generalización. |
- | Si escribimos la definición de // | + | sumatoria xs = acumular (+) 0 xs |
+ | productoria xs = acumular (*) 1 xs | ||
+ | concatenaInt xs = acumular (++) [] xs | ||
- | * Generalizar // | + | O bien aplicando secciones, es decir, sin escribir los argumentos obvios: |
- | | + | |
- | mapa.longitud.[[], | + | productoria = acumular |
+ | concatenaInt = acumular | ||
- | La escribamos: | ||
- | < | + | ===== Ejercicios ===== |
- | mapa :: (a -> b) -> [a] -> [b] | + | |
- | mapa f [] = | + | |
- | mapa f (x: | + | |
- | </ | + | |
- | + | | |
- | ==== Filtros (filter) ==== | + | |
- | + | ||
- | Lo mismo para // | + | |
- | + | ||
- | * Generalice la función // | + | |
- | + | ||
- | probar con filtro.esMultiplo2.[1, | + | |
- | filtro.(==0).[1, | + | |
- | + | ||
- | La escribamos: | + | |
- | + | ||
- | < | + | |
- | filtro :: (a-> | + | |
- | filtro p [] = | + | |
- | filtro p (x:xs) = | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | + | ||
- | ==== Acumuladores (fold) ==== | + | |
- | + | ||
- | La generalización de los acumuladores a distintos tipos es un poco más complicada. | + | |
- | Veamos la función de acumulación que dice si todos los elementos son 0 y 1. | + | |
- | + | ||
- | < | + | |
- | todos0y1 :: [Int] -> Bool | + | |
- | todos0y1 [] = True | + | |
- | todos0y1 (x:xs) = (x==0 || x==1) && todos0y1 xs | + | |
- | </ | + | |
- | + | ||
- | Detectamos: | + | |
- | * Un " | + | |
- | * Una función de acumulación que a partir del elemento actual y lo acumulado en la llamada recursiva sobre //xs//, obtiene el valor de lo acumulado en el total //x:xs//. | + | |
- | + | ||
- | Podemos reescribirla de la siguiente manera para que la función de acumulación sea más explícita. | + | |
- | + | ||
- | < | + | |
- | ceroUnoYAnteriores :: Int -> Bool -> Bool | + | |
- | ceroUnoYAnteriores x b = (x==0 || x==1) && b | + | |
- | + | ||
- | todos0y1' | + | |
- | todos0y1' | + | |
- | todos0y1' | + | |
- | </ | + | |
- | + | ||
- | La defunición general sería: | + | |
- | + | ||
- | * Generalice la función anterior para operadores y listas de cualquier tipo. Definir // | + | |
- | + | ||
- | probar con todos los ejemplos de las versiones menos generales. | + | |
- | + | ||
- | Nuevamente la escribimos. | + | |
- | + | ||
- | < | + | |
- | acumula :: (a-> | + | |
- | acumula f z [] = | + | |
- | acumula f z (x:xs) = | + | |
- | </ | + | |
- | + | ||
- | ===== Reescribiendo funciones usando map, fold y filter ===== | + | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | ==== Ejercicios ==== | + | |
- | + | ||
- | | + | |
* Reescribir ambas utilizando aplicación parcial sobre //mapa// para evitar escribir el argumento de la lista. | * Reescribir ambas utilizando aplicación parcial sobre //mapa// para evitar escribir el argumento de la lista. | ||
- | * Utilizando //mapa// escribir la función //largos :: [String] -> [Int]// que dada una lista de cadenas, retorna la lista con la longitud de cada una. | + | * Utilizando //aplicar// escribir la función //largos :: [String] -> [Int]// que dada una lista de strings, retorna la lista con la longitud de cada una. //Ayuda: recordar que los strings son listas de caracteres.// |
- | * Escribir // | + | * Escribir // |
- | * Reescribir ambas utilizando aplicación parcial sobre //mapa// para evitar escribir el argumento de la lista. | + | * Reescribir ambas utilizando aplicación parcial sobre //aplicar// para evitar escribir el argumento de la lista. |
- | * Escribir // | + | * Escribir // |
- | * Escribir // | + | * Escribir // |
- | * Escribir // | + | * Escribir // |
- | * Escribir // | + | * Escribir // |
- | * Escribir //reversa// usando //acumula//. | + | * Escribir //reversa// usando //acumular//. |
- | * **(DIFÍCIL)** Escribir //mapa// y //filtro// usando //acumula//. | + | * **(DIFÍCIL)** Escribir //aplicar// y //filtrar// usando //acumular//. |
+ | * Definir la función // | ||
+ | * Definir la función // | ||
+ | * Definir la función // | ||
+ | * Definir la función // | ||
+ | * Definir la función // | ||
+ | * Definir la función // | ||
+ | * Definir la función // | ||
+ | * Definir la función // |
introalg/taller08_4.1210452623.txt.gz · Última modificación: 2018/08/10 03:03 (editor externo)