Listas y Recursión Taller de Álgebra I Primer Cuatrimestre de 2015
Un nuevo tipo: Listas Tipo Lista Las listas pueden contener elementos de cualquier tipo (incluso listas) [1] :: [Integer] [1, 2] :: [Integer] [1.1, 2, 4, 3.2] :: [Float] [[1], [2,3], [], [1,1000,2,0]] :: [[Integer]] [1, a ] NO ES UNA LISTA VÁLIDA, por qué?
Un nuevo tipo: Listas Tipo Lista Las listas pueden contener elementos de cualquier tipo (incluso listas) [1] :: [Integer] [1, 2] :: [Integer] [1.1, 2, 4, 3.2] :: [Float] [[1], [2,3], [], [1,1000,2,0]] :: [[Integer]] [1, a ] NO ES UNA LISTA VÁLIDA, por qué? Tipar las siguientes expresiones [(1,2), (3,4), (5,2)] [maximo 2 3, fst (2+2, 3+4), 3+4-3/4] [ [], [], [], [], [] ] [] [if True then False else True, 3 > 3 && 4 < 2] [undefined]
Ejercicios Otras formas de definir listas Prueben las siguientes expresiones en GHCI [1..100] [1,3..100] [100..1] Cómo harían la lista que va entre 1 y -100?
Ejercicios Otras formas de definir listas Prueben las siguientes expresiones en GHCI [1..100] [1,3..100] [100..1] Cómo harían la lista que va entre 1 y -100? Definir las siguientes funciones listar :: a -> a -> a -> [a] que toma 3 elementos y los convierte en una lista. rangodepaso :: Integer -> Integer -> Integer -> [Integer] que, dados 3 números (n1, n2, n3), devuelve la lista resultante de crear el rango con bordes n1 y n2 (inclusive) y paso n3
Operaciones Algunas operaciones head :: [a] -> a tail :: [a] -> [a] (:) :: a -> [a] -> [a] (++) :: [a] -> [a] -> [a] length :: [a] -> Int reverse :: [a] -> [a]
Operaciones Algunas operaciones head :: [a] -> a tail :: [a] -> [a] (:) :: a -> [a] -> [a] (++) :: [a] -> [a] -> [a] length :: [a] -> Int reverse :: [a] -> [a] Tipar y reducir las siguientes expresiones head [(1,2), (3,4), (5,2)] tail [1,2,3,4,4,3,2,1] head [] head [1,2,3] : [2,3] [True, True] ++ [False, False] [1,2] : []
Recursión Hasta ahora, especificamos funciones que consistían en expresiones sencillas. Sin embargo, el tipo de funciones que hicimos hasta la clase pasada no permite programar todas las funciones computables.
Recursión Hasta ahora, especificamos funciones que consistían en expresiones sencillas. Sin embargo, el tipo de funciones que hicimos hasta la clase pasada no permite programar todas las funciones computables. Por ejemplo, cómo es una función en Haskell para calcular el factorial de un número entero?
Recursión Hasta ahora, especificamos funciones que consistían en expresiones sencillas. Sin embargo, el tipo de funciones que hicimos hasta la clase pasada no permite programar todas las funciones computables. Por ejemplo, cómo es una función en Haskell para calcular el factorial de un número entero? n! = n k k=1
Recursión Hasta ahora, especificamos funciones que consistían en expresiones sencillas. Sin embargo, el tipo de funciones que hicimos hasta la clase pasada no permite programar todas las funciones computables. Por ejemplo, cómo es una función en Haskell para calcular el factorial de un número entero? n! = n k, n! = k=1 { 1 si n = 0 n (n 1)! si no
Recursión Hasta ahora, especificamos funciones que consistían en expresiones sencillas. Sin embargo, el tipo de funciones que hicimos hasta la clase pasada no permite programar todas las funciones computables. Por ejemplo, cómo es una función en Haskell para calcular el factorial de un número entero? n! = n k, n! = k=1 { 1 si n = 0 n (n 1)! si no La segunda definición de factorial involucra a esta misma función del lado derecho!
Definiciones recursivas
Definiciones recursivas factorial :: Int -> Int
Definiciones recursivas factorial :: Int -> Int factorial n n == 0 =
Definiciones recursivas factorial :: Int -> Int factorial n n == 0 = 1
Definiciones recursivas factorial :: Int -> Int factorial n n == 0 = 1 factorial n n > 0 =
Definiciones recursivas factorial :: Int -> Int factorial n n == 0 = 1 factorial n n > 0 = n * factorial (n-1)
Definiciones recursivas Propiedades de una definición recursiva: 1 Tiene que tener uno o más casos base. 2 Las llamadas recursivas del lado derecho tienen que acercarse al caso base, con relación a los parámetros del lado izquierdo de la ecuación.
Definiciones recursivas Propiedades de una definición recursiva: 1 Tiene que tener uno o más casos base. 2 Las llamadas recursivas del lado derecho tienen que acercarse al caso base, con relación a los parámetros del lado izquierdo de la ecuación. En cierto sentido, la recursión es el equivalente computacional de la inducción para las demostraciones.
Más sobre la función factorial Dado que las ecuaciones se evalúan en secuencia, también podemos definir: factorial :: Int -> Int factorial 0 = 1 factorial n = n * factorial (n -1)
Más sobre la función factorial Dado que las ecuaciones se evalúan en secuencia, también podemos definir: factorial :: Int -> Int factorial 0 = 1 factorial n = n * factorial (n -1) Observar que factorial 70 = 0 Por qué sucede esto?
Más sobre la función factorial Dado que las ecuaciones se evalúan en secuencia, también podemos definir: factorial :: Int -> Int factorial 0 = 1 factorial n = n * factorial (n -1) Observar que factorial 70 = 0 Por qué sucede esto? factorial :: Integer -> Integer factorial 0 = 1 factorial n = n * factorial (n -1)
Otro ejemplo clásico Consideremos la sucesión de Fibonacci: F 0 = 0 F 1 = 1 F n = F n 1 + F n 2 n 2 Programar en Haskell una función que dado n calcule F n fib :: Integer -> Integer Mostrar cómo reduce la siguiente expresión fib (1+2)?? (utilizando evaluación Lazy)
Asegurarse de llegar a un caso base Consideremos este programa recursivo para determinar si un número es par: par :: Int -> Bool par 0 = True par n = par (n-2) Qué problema tiene esta función?
Asegurarse de llegar a un caso base Consideremos este programa recursivo para determinar si un número es par: par :: Int -> Bool par 0 = True par n = par (n-2) Qué problema tiene esta función? Cómo se arregla?
Asegurarse de llegar a un caso base Consideremos este programa recursivo para determinar si un número es par: par :: Int -> Bool par 0 = True par n = par (n-2) Qué problema tiene esta función? Cómo se arregla? par 0 = True par 1 = False par n = par (n-2) par 0 = True par n = not (par (n-1))
Recursión sobre listas No todo son números Podremos implementar la función que suma todos los elementos de una lista?
Recursión sobre listas No todo son números Podremos implementar la función que suma todos los elementos de una lista? suma :: [Integer] -> Integer suma lista length lista == 0 = 0 suma lista otherwise = head lista + suma (tail lista) Implementemos las siguientes funciones Implementar y dar el tipo de la productoria de una lista. Implementar la función reverso :: [a] -> [a] Mostrar los pasos de reducción para la evaluación de reverso [ a, b, c ] Implementar la función capicua :: [Integer] -> Bool que devuelve verdadero si el reverso de una lista de números es la misma lista.
Ejercicios 1 Escribir una función que dados dos n, m N devuelva el combinatorio ( n m). Hacerlo usando la igualdad ( ) ( n m = n 1 ) ( m + n 1 m 1). 2 Escribir una función que dado n N sume los primeros n números impares. Ej: sumaimpares 3 1 + 3 + 5 9. 3 Escribir una función que dado n N sume los cuadrados de los primeros n números impares. Ej: sumacuadradosimpares 3 1ˆ2 + 3ˆ2 + 5ˆ2 1 + 9 + 25 35. 4 (*) Escribir una función que dado n N sume los impares tales que su cuadrado sea menor que n. Ej: sumaimparescuadradosmenoresa 30 1 + 3 + 5 9. 5 Escribir una función para determinar recursivamente si un número es múltiplo de 3. No se puede usar las funciones mod y div para resolver este ejercicio. 6 Escribir una función recursiva que no termine si se ejecuta con números negativos. 7 Escribir una función para calcular n!! = n (n 2)(n 4)... 2. La función se debe indefinir para los números impares. 8 Implementar la función todosverdaderos :: [Bool] -> Bool que devuelve verdadero sólo si todos los elementos de la listas son verdaderos. Ejemplo todosverdaderos [True, 2 < 3, 4 + 2 > 5] True. 9 Implementar la función tomarn :: Int -> [a] -> [a] que retorna la lista de los primeros n elementos de la lista de entrada (para entender el funcionamiento revisar su equivalente en haskell: take).