Iteración, recursión y punto fijo

En esta relación de ejercicios se muestra cómo se pueden transformar programas iterativos (con bucles while o for) en programas en recursivos. Para cada uno de los bucles, se elige una función y se pide definirla usando el bucle (en Python), buscar una definición recursiva que sea semejante a la anterior, definir el patrón que abstrae el bucle, definirla con el patrón y aplicar el patrón a otras funciones. Finalmente, se estudia cómo definir algunas de las anteriores funciones usando el menor punto fijo.

La relación está elaborado como complemento del tema Funciones de orden superior del curso de Informática de primero del Grado en Matemáticas.

El bucle while con un parámetro

Nota [Parte impar]. Todo número entero n se puede escribir como m*2^k, con m impar. Se dice que m es la parte impar de n. Por ejemplo, la parte impar de 40 es 5 porque 40 = 5*2^3.

Ejercicio 1 [Parte impar con while en Python]. Definir en Python, usando un blucle while, la función parteImpar tal que parteImpar(n) es la parte impar de n.

Solución:

Ejercicio 2 [Parte impar por recursión]. Definir, por recursión, la función
parteImpar :: Int -> Int
tal que (parteImpar n) es la parte impar de n. Por ejemplo,
parteImpar 40 == 5

Solución:

Ejercicio 3 [El bucle while1]. Definir la función
while1 :: (a -> Bool) -> (a -> a) -> a -> a
tal que (while1 p f x) es el resultado de aplicar la función f a x mientras cumple la propiedad p. Por ejemplo,
while1 (<1000) (*2) 1 == 1024

Solución:

Ejercicio 4 [Parte impar con el bucle while1]. Redefinir, usando while1, la función parteImpar.

Solución:

Nota [La órbita de Collatz]. El sucesor de Collatz de un número n es n/2, si n es par y 3n+1 , en caso contrario. La órbita de un número se obtiene escribiendo los sucesivos sucesores de Collatz hasta llegar a 1. Por ejemplo, la órbita de Collatz de 7 es 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1.

Ejercicio 5 [La órbita de Collatz con while en Python]. Definir en Python, usando while, la función collatz tal que collatz(n) es la órbita de Collatz de n. Por ejemplo,
collatz(7) == [7,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1]

Solución:

Ejercicio 6 [La órbita de Collatz por recursión]. Definir, mediante recursión, la función
collatz :: Integer -> [Integer]
tal que (collatz n) es la órbita de Collatz de n. Por ejemplo,
collatz 7 == [7,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1]

Solución:

Ejercicio 7 [La órbita de Collatz con while1]. Definir, usando while1, la
función
collatz :: Integer -> [Integer]
tal que (collatz n) es la órbita de Collatz de n. Por ejemplo,
collatz 7 == [7,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1]

Solución:

Ejercicio 8 [El menor punto fijo por recursión]. Definir, por recursión, la función
mpf :: Eq a => (a -> a) -> a -> a
tal que (mpf f x) es el menor punto fijo de f respecto de x. Por ejemplo,
mpf (\x -> if x < 10 then x else (div x 10)) 325 == 3
mpf (\x -> if even x then (div x 2) else x) 24 == 3

Solución:

Ejercicio 9 [El menor punto fijo con while1]. Definir, con while1, la función
mpf :: Eq a => (a -> a) -> a -> a
tal que (mpf f x) es el menor punto fijo de f respecto de x. Por ejemplo,
mpf (\x -> if x < 10 then x else (div x 10)) 325 == 3
mpf (\x -> if even x then (div x 2) else x) 24 == 3

Solución:

El bucle while con dos parámetros

Ejercicio 10 [Suma impares con bucle while en Python]. Definir en Python, usando un bucle while, la función sumaImpares tal que sumaImpares(n) es la suma de los n primeros números impares. Por ejemplo,
sumaImpares(3) == 9
sumaImpares(4) == 16

Solución:

Ejercicio 11 [Suma impares por recursión]. Definir en Haskell la función
sumaImpares :: Int -> Int

que traduzca la definición anterior.

Solución:

Ejercicio 12 [El bucle while2] Definir la función
while2 :: (a -> b -> Bool) -> (a -> b -> (a,b)) -> a -> b -> b
tal que (while2 p f x y) aplica f a x e y mientras que se cumple la propiedad p y devuelve y cuando no se cumple. Por ejemplo,
(while2 (\x y -> x<3) (\x y -> (x+1,x+y))) 0 0 == 3
(while2 (\x y -> x<4) (\x y -> (x+1,x+y))) 0 0 == 6

El procedimiento de evaluación de (while2 p f x y) es el siguiente

  • si se verifica (p x y), evalúa (f x y) que dará un par (x1,y1)
  • si se verifica (p x1 y1), evalúa (f x1 y1) que dará un par (x2,y2)
  • y así hasta que llegue a un par (xn,yn) tal que no se verifique (p xn yn), en cuyo caso devuelve yn.

Solución:

Ejercicio 13 [Suma impares con while2]. Redefinir, usando while2, la función sumaImpares.

Solución:

Ejercicio 14 [El algoritmo de Euclides con while en Python]. Definir en Python la función mcd tal que mcd(x,y) es el máximo común divisor de x e y, calculado mediante el algoritmo de Euclides.

Solución:

Ejercicio 15 [El algoritmo de Euclides por recursión]. Definir la función
mcd :: Int -> Int -> Int

tal que mcd(x,y) es el máximo común divisor de x e y, calculado mediante el algoritmo de Euclides.

Solución:

Ejercicio 16 [El algoritmo de Euclides con while2]. Redefinir, usando while2, la función mcd.

Solución:

Ejercicio 17 [El factorial con while en Python]. Definir en Python, usando while, la función fact tal que fact(n) es el factorial de n. Por ejemplo,
fact(4) == 24

Solución:

Ejercicio 18 [El factorial por recursión]. Definir, por recursión, la función
fact :: Integer -> Integer
tal que (fact n) es el factorial de n. Por ejemplo,
fact 4 == 24

Solución:

Ejercicio 19 [El factorial con while2]. Redefinir, con while2, la función fact.

Solución:

El bucle while con tres parámetros

Ejercicio 20 [Fibonacci con while en Python]. Definir la función fib tal que fib(n) es el n-ésimo término de la sucesión de Fibonacci. Por ejemplo,
[fib(n) for n in range(10)] == [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

Solución:

Ejercicio 21 [Fibonacci por recursión]. Definir, por recursión, la función
fib :: Int -> Int
tal que (fib n) es el n-ésimo término de la sucesión de Fibonacci. Por ejemplo,
[fib n | n <- [0..9]] == [0,1,1,2,3,5,8,13,21,34]

Solución:

Ejercicio 22 [El bucle while3]. Definir la función
while3 :: (a -> b -> c -> Bool) -> (a -> b -> c -> (a,b,c)) -> a -> b -> c -> c
tal que (while3 p f x y z) es una generalización de while2 con tres parámetros. Por ejemplo,
while3 (\n x y -> n > 0)(\n x y -> (n-1,y,x+y)) 5 0 1 == 8
while3 (\n x y -> n > 0)(\n x y -> (n-1,y,x+y)) 6 0 1 == 13
while3 (\n x y -> n > 0)(\n x y -> (n-1,y,x+y)) 7 0 1 == 21

Solución:

Ejercicio 23 [Fibonacci con while3]. Redefinir, con while3, la función fib.

Solución:

El bucle for con un parámetro

Ejercicio 24 [El factorial con for en Python]. Definir en Python, usando for, la función fact tal que fact(n) es el factorial de n. Por ejemplo,
fact(4) == 24

Solución:

Ejercicio 25 [El bucle for]. Definir la función
for :: [a] -> (a -> b -> b) -> b -> b
tal que (for xs f y) es el resultado de iterar f sobre los elementos de xs a partir de y; es decir, si xs es [x(1),...,x(n)] entonces (for xs f y) es (f x(n) (f x(n-2) (... (f x(2) (f x(1) y))))). Por ejemplo,
(for [1..4] (\x s -> x+s)) 0 == 10
(for [1..4] (\x s -> x*s)) 1 == 24

Solución:

Ejercicio 26 [El factorial con for]. Reefinir, usando for, la función fact.

Solución:

El bucle for con dos parámetros

Ejercicio 27 [Fibonacci con for en Python]. Definir en Python, usando for, la función fib tal que fib(n) es el n-ésimo término de la sucesión de Fibonacci. Por ejemplo,
[fib(n) for n in range(10)] == [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

Solución:

Ejercicio 28 [El bucle for2]. Definir el bucle for con 2 parámetros. Por ejemplo.
for2 [1..9] (\x y z -> (x+y,y:z)) 0 [] == [36,28,21,15,10,6,3,1,0]
for2 [1..7] (\x y z -> (x*y,y:z)) 1 [] == [720,120,24,6,2,1,1]

Solución:

Ejercicio 29 [Fibonacci con for2]. Redefinir, con for2, la función fib.

Solución:

Recursión y puntos fijos

Nota. En esta sección se proponen ejercicios para eliminar la recursión mediante puntos fijos; en concreto, usando la función fix tal que (fix f) es el menor punto fijo de f. La función fix está definida en la librería Data.Function como

Ejercicio 30 [Factorial mediante fix]. Definir, usando fix, la función
fact :: Integer -> Integer
tal que (fact n) es el factorial de n. Por ejemplo,
[fact n | n <- [0..6]] == [1,1,2,6,24,120,720]

Solución:

Ejercicio 31 [Fibonacci mediante fix]. Definir, usando fix, la función
fib :: Int -> Int
tal que (fib n) es el n-ésimo término de la sucesión de Fibonacci. Por ejemplo,
[fib n | n <- [0..9]] == [0,1,1,2,3,5,8,13,21,34]

Solución:

Ejercicio 32 [La órbita de Collatz mediante fix]. Definir, usando fix, la función
collatz :: Integer -> [Integer]
tal que (collatz n) es la órbita de Collatz de n. Por ejemplo,
collatz 7 == [7,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1]

Solución:

Ejercicio 33 [Suma impares mediante fix]. Definir, usando fix, la función
sumaImpares :: Int -> Int
tal que (sumaImpares n) es la suma de los primeros n números impares. Por ejemplo,
sumaImpares 3 == 9
sumaImpares 4 == 16

Solución:

Referencias