introalg:taller08_6
Diferencias
Muestra las diferencias entre dos versiones de la página.
Próxima revisión | Revisión previa | ||
introalg:taller08_6 [2008/06/03 02:24] – creado laura | introalg:taller08_6 [2018/08/10 03:03] (actual) – editor externo 127.0.0.1 | ||
---|---|---|---|
Línea 1: | Línea 1: | ||
====== Clase 6 ====== | ====== Clase 6 ====== | ||
- | ===== Optimización | + | ===== Mejorando al eficiencia (optimización |
+ | |||
+ | Vimos que hay diferentes formas de definir una misma función. Estas distintas definiciones pueden resultar muy distintas en eficiencia. Vamos a ver algunas estrategias para mejorar la eficiencia de las funciones. | ||
==== Siendo verdaderamente recursivos en dos argumentos ==== | ==== Siendo verdaderamente recursivos en dos argumentos ==== | ||
Línea 36: | Línea 38: | ||
==== Explotando el absorbente ==== | ==== Explotando el absorbente ==== | ||
+ | |||
+ | Otra forma de optimizar el cómputo es cortando la recursión en el momento en que el resultado queda determinado y no puede ser cambiado en ninguna iteración posterior de la función, independientemente de los valores que la función encuentre. Eso pasa típicamente cuando se encuentra el valor absorbente del operador que estemos usando. | ||
+ | |||
+ | Recordemos que el absorbente es el contrario exacto del neutro: para una determinada operación binaria, aplicar la operación a cualquier valor y el absorbente devuelve siempre el absorbente. | ||
+ | |||
+ | Veamos un ejemplo con la función //existe//. Cuando la habíamos definido con recursión clásica, la definimos así: | ||
+ | |||
+ | existe :: Eq a => a -> [a] -> Bool | ||
+ | existe a [] = False | ||
+ | existe a (x:xs) = x == a || existe a xs | ||
+ | |||
+ | o bien, usando foldr: | ||
+ | |||
+ | existe' | ||
+ | existe' | ||
+ | where | ||
+ | igual :: Eq a => a -> a -> Bool | ||
+ | igual x y = x == y | ||
+ | |||
+ | Sin embargo, hay una forma más eficiente de definirla: | ||
+ | |||
+ | existe'' | ||
+ | existe'' | ||
+ | existe'' | ||
+ | | (x == a) == False = existe'' | ||
+ | |||
+ | De esta forma, la recursión se corta en dos casos: cuando llegamos al final, en que se devuelve el neutro (//False//) o cuando encontramos al absorbente (//True//). En el caso recursivo no se acumula ningún resultado, aunque esta función es un acumulador, ya que sabemos de antemano que sólo puede haber dos resultados: el neutro o el absorbente, y tenemos definidos los casos en que nos va a devolver el uno o el otro. | ||
+ | |||
+ | Podemos aplicar esta estrategia de optimización para los casos de acumuladores con un absorbente: la multiplicación, | ||
+ | |||
+ | En el caso concreto de Haskell, este tipo de optimización no es especialmente eficiente, por la forma como funciona Haskell, sin embargo, esta estrategia dá muy buena optimización para otros lenguajes. | ||
+ | |||
===== Tipos definidos por el usuario ===== | ===== Tipos definidos por el usuario ===== | ||
- | Main> | + | Para este apartado vamos a usar las filminas de [[http:// |
- | (==) :: Eq a ⇒ a → a → Bool | + | |
- | Main> :t (+) | + | ===== Ejercicios de repaso ===== |
- | (+) :: Num a ⇒ a → a → a | + | |
+ | |||
+ | ==== Recursión en dos argumentos ==== | ||
+ | |||
+ | * Definir la función // | ||
+ | |||
+ | * Definir la función // | ||
+ | |||
+ | * Definir la función // | ||
+ | |||
+ | * Definir la función // | ||
+ | |||
+ | * Definir la función //fusiona :: Ord a => [a] -> [a] -> [a]//, que dadas dos listas nos devuelve una lista que combina las dos anteriores con sus elementos ordenados de menor a mayor, sin duplicados. | ||
+ | |||
+ | * Definir la función // | ||
+ | |||
+ | * Definir la función // | ||
introalg/taller08_6.1212459863.txt.gz · Última modificación: 2018/08/10 03:03 (editor externo)