====== Clase 2 ====== ===== Plan para hoy ===== * Repaso de algunas soluciones de la clase anterior. * Sintáxis de //pattern matching//. * Trabajar sobre programas recursivos numéricos y con listas. * Resolución de ejercicios. ===== Algunas soluciones de la clase anterior ====== Veamos algunas soluciones presentadas [[introalg:rincon | Wiki de Scripts Haskell]]. Notamos * No hay una única forma de resolver un problema. * Como hacer **control de los parámetros de entrada**. * Cláusula **''otherwise''** para análisis por casos. * **Comentarios** en el código. * Uso del **''if-then-else''** en vez de análisis por casos. * ¿**Guardas //exhaustivas//**?. Uso del cálculo proposicional. * No se usaron **definiciones locales** para la función de cálculo de área. ** Se aprende muchísimo //leyendo detenidamente código bien escrito// ** ===== Clase ===== Hasta ahora vimos programas funcionales **no recursivos**, que se basan en la //composición de funciones// de la bibilioteca (''Prelude'') y las definidas en scripts de Haskell. Veamos la última función no recursiva que vamos a plantear, que sirve para presentar el mecanismo de **pattern matching**. Ejercicio 8 Definir la función cabeza:[A]->A que devuelve el primer elemento de la lista. Por ejemplo ''cabeza [4,3,2]'' reduce a la //forma canónica// '4'. El mecanismo básico para poder **destruir** una lista en partes es el //pattern matching//, que podemos pensarlo como una definición por casos, que es capaz de dividir la lista en su **cabeza** y **cola** cabeza :: [a] -> a cabeza (x:xs) = x Podemos agregar esta definición a un script de Haskell con nombre ''practico8.hs''.\\ Evaluemos algunos casos. Main> cabeza [1,2,3] 1 Main> cabeza "minombre" 'm' Main> cabeza [] Program error: pattern match failure: cabeza [] De la misma forma podemos hacer la función ''cola'' solo que devolviendo ''xs'' en lugar de x. cola :: [a] -> [a] cola (x:xs) = xs También tenemos //pattern matching// numérico. \\ Vemos como escribir una funcion que devuelve verdadero si y solo si el número es 0 o 1 (puede ser útil para el ejercicio 17) ceroOuno :: Int -> Bool ceroOuno 0 = True ceroOuno 1 = True ceroOuno x = False ==== Programas Recursivos ==== Tomemos el ejercicio 10 del Práctico 8. Defina la función duplicar::[Num]->[Num] que dada una lista duplica cada uno de sus elementos. Ejemplo: duplicar [2,4,8] = [4,8,16] Usamos un planteamiento //inductivo o recursivo// y //pattern matching// para * Definir un **caso base** (lista vacía ''[]'') * Definir el **caso inductivo** (la lista tiene al menos un elemento, siendo el primero ''x'' y el resto de la lista ''xs'') duplicar :: [Int] -> [Int] duplicar [] = [] -- caso base duplicar (x:xs) = 2*x : xs -- caso inductivo Probamos la definición Main> duplicar [2,3,4] [4,3,4] ¿Donde está el error? Simplemente olvidamos duplicar la "cola" de la lista. \\ Lo arreglamos rápidamente, aplicando **la misma definición de duplicar a la lista restante**. Veamos ahora el ejercicio 12. Defina la función sumatoria:[Num]->Num que dada una lista devuelve la suma de sus elementos. La estrategia es la misma que en el caso anterior * Definir caso base para la lista vacía. * Definir el caso inductivo para la lista con al menos un elemento, suponiendo que ya esta definido para longitudes menores. sumatoria :: [Int] -> Int sumatoria [] = 0 sumatoria (x:xs) = x + sumatoria xs Vemos algunos ejemplos Main> sumatoria [1,2,3] 6 Main> sumatoria (duplicar (duplicar [1,2,3])) 24 Main> sumatoria ((duplicar.duplicar) [1,2,3]) 24 Veamos el siguiente código y tratemos de entender que es lo que //computa// desdeHasta :: Int -> Int -> [Int] desdeHasta n m | n>m = [] | n==m = [n] | n Num -> [Num]// que dada una lista y un número //r// multiplica cada uno de los elementos por //r//. Ejemplo //multiplicar.[2,4,8].3 = [6,12,24]//. Notar que generaliza //duplicar//. * (P8-E12) Defina la función promedio //promedio:[Num] -> Num// que dada una lista de números, calcule su promedio. * (P8-E16) (*) c) Modificar la guarda de ''n>m'' en ''desdeHasta'' para que si esto pasa retorne la lista descendente.