Tema 6: Funciones recursivas

Probando

Librerías auxiliares

import Data.Char

1 Recursión numérica

Recursión numérica: El factorial

factorial :: Integer -> Integer
factorial 0 = 1
factorial n = n * factorial (n-1)
factorial 3
= 3 * (factorial 2)
= 3 * (2 * (factorial 1))
= 3 * (2 * (1 * (factorial 0)))
= 3 * (2 * (1 * 1))
= 3 * (2 * 1)
= 3 * 2
= 6

Recursión numérica: El producto

por :: Int -> Int -> Int
m `por` 0  = 0
m `por` n  = m + (m `por` (n-1))
3 `por` 2
= 3 + (3 `por` 1)
= 3 + (3 + (3 `por` 0))
= 3 + (3 + 0)
= 3 + 3
= 6

2 Recusión sobre lista

Recursión sobre listas: La función product

product :: Num a => [a] -> a
product []     = 1
product (n:ns) = n * product ns
product [7,5,2]
= 7 * (product [5,2])
= 7 * (5 * (product [2]))
= 7 * (5 * (2 * (product [])))
= 7 * (5 * (2 * 1))
= 7 * (5 * 2)
= 7 * 10
= 70

Recursión sobre listas: La función length

length :: [a] -> Int
length []     = 0
length (_:xs) = 1 + length xs
length [2,3,5]
= 1 + (length [3,5])
= 1 + (1 + (length [5]))
= 1 + (1 + (1 + (length [])))
= 1 + (1 + (1 + 0))
= 1 + (1 + 1)
= 1 + 2
= 3

Recursión sobre listas: La función reverse

reverse :: [a] -> [a]
reverse []     = []
reverse (x:xs) = reverse xs ++ [x]
reverse [2,5,3]
= (reverse [5,3]) ++ [2]
= ((reverse [3]) ++ [5]) ++ [2]
= (((reverse []) ++ [3]) ++ [5]) ++ [2]
= (([] ++ [3]) ++ [5]) ++ [2]
= ([3] ++ [5]) ++ [2]
= [3,5] ++ [2]
= [3,5,2]

Recursión sobre listas: ++

(++) :: [a] -> [a] -> [a]
[]     ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)
[1,3,5] ++ [2,4]
= 1:([3,5] ++ [2,4])
= 1:(3:([5] ++ [2,4]))
= 1:(3:(5:([] ++ [2,4])))
= 1:(3:(5:[2,4]))
= 1:(3:[5,2,4])
= 1:[3,5,2,4]
= [1,3,5,2,4]

Recursión sobre listas: Inserción ordenada

inserta 5 [2,4,7,3,6,8,10] == [2,4,5,7,3,6,8,10]
inserta :: Ord a => a -> [a] -> [a]
inserta e []                  = [e]
inserta e (x:xs) | e <= x     = e : (x:xs)
                 | otherwise  = x : inserta e xs
inserta 4 [1,3,5,7]
= 1:(inserta 4 [3,5,7])
= 1:(3:(inserta 4 [5,7]))
= 1:(3:(4:(5:[7])))
= 1:(3:(4:[5,7]))
= [1,3,4,5,7]

Recursión sobre listas: Ordenación por inserción

ordena_por_insercion [2,4,3,6,3] == [2,3,3,4,6]
ordena_por_insercion :: Ord a => [a] -> [a]
ordena_por_insercion []     = []
ordena_por_insercion (x:xs) =
    inserta x (ordena_por_insercion xs)
  ordena_por_insercion [7,9,6] =
= inserta 7 (inserta 9 (inserta 6 []))
= inserta 7 (inserta 9 [6])
= inserta 7 [6,9]
= [6,7,9]

3 Recursión sobre varios argumentos

Recursión sobre varios argumentos: La función zip

zip :: [a] -> [b] -> [(a, b)]
zip []     _      = []
zip _      []     = []
zip (x:xs) (y:ys) = (x,y) : zip xs ys
zip [1,3,5] [2,4,6,8]
= (1,2) : (zip [3,5] [4,6,8])
= (1,2) : ((3,4) : (zip [5] [6,8]))
= (1,2) : ((3,4) : ((5,6) : (zip [] [8])))
= (1,2) : ((3,4) : ((5,6) : []))
= [(1,2),(3,4),(5,6)]

Recursión sobre varios argumentos: La función drop

drop :: Int -> [a] -> [a]
drop 0 xs     = xs
drop n []     = []
drop n (x:xs) = drop (n-1) xs
drop 2 [5,7,9,4]       |        drop 5 [1,4]
= drop 1 [7,9,4]       |        = drop 4 [4]
= drop 0 [9,4]         |        = drop 1 []
= [9,4]                |        = []

4 Recursión múltiple

Recursión múltiple: La función de Fibonacci

fibonacci 8  ==  21
fibonacci :: Int -> Int
fibonacci 0 = 0
fibonacci 1 = 1
fibonacci n = fibonacci (n-2) + fibonacci (n-1)

Recursión múltiple: Ordenación rápida

ordena :: (Ord a) => [a] -> [a]
ordena [] = []
ordena (x:xs) =
    (ordena menores) ++ [x] ++ (ordena mayores)
    where menores = [a | a <- xs, a <= x]
          mayores = [b | b <- xs, b > x]

5 Recursión mutua

Recursión mutua: Par e impar

par :: Int -> Bool
par 0 = True
par n = impar (n-1)

impar :: Int -> Bool
impar 0 = False
impar n = par (n-1)
impar 3               |         par 3
= par 2               |         = impar 2
= impar 1             |         = par 1
= par 0               |         = impar 0
= True                |         = False

Recursión mutua: Posiciones pares e impares

pares :: [a] -> [a]
pares []     = []
pares (x:xs) = x : impares xs

impares :: [a] -> [a]
impares []     = []
impares (_:xs) = pares xs

6 Heurísticas para las definiciones recursivas

Aplicación del método: La función product

product :: [Int] -> Int
product :: [Int] -> Int
product []     =
product (n:ns) =
product :: [Int] -> Int
product []     = 1
product (n:ns) =
product :: [Int] -> Int
product []     = 1
product (n:ns) = n * product ns
product :: Num a => [a] -> a
product []     = 1
product (n:ns) = n * product ns

Aplicación del método: La función drop

drop :: Int -> [a] -> [a]
drop :: Int -> [a] -> [a]
drop 0 []     =
drop 0 (x:xs) =
drop n []     =
drop n (x:xs) =
drop :: Int -> [a] -> [a]
drop 0 []     = []
drop 0 (x:xs) = x:xs
drop n []     = []
drop n (x:xs) =
drop :: Int -> [a] -> [a]
drop 0 []     = []
drop 0 (x:xs) = x:xs
drop n []     = []
drop n (x:xs) = drop n xs
drop :: Integral b => b -> [a] -> [a]
drop 0 xs     = xs
drop n []     = []
drop n (_:xs) = drop n xs

Aplicación del método: La función init

init :: [a] -> [a]
init :: [a] -> [a]
init (x:xs) =
init :: [a] -> [a]
init (x:xs) | null xs   = []
            | otherwise =
init :: [a] -> [a]
init (x:xs) | null xs   = []
            | otherwise = x : init xs
init :: [a] -> [a]
init [_]    = []
init (x:xs) = x : init xs

7 Bibliografía



Universidad de Sevilla
José A. Alonso Jiménez
Grupo de Lógica Computacional
Dpto. de Ciencias de la Computación e I.A.
Universidad de Sevilla