El razonamiento es el mismo, solo que las expresiones son un poco más complicadas en este caso. Hay que tratar de no marearse.
Funciones usadas para referencia:
take :: Int -> [a] -> [a]
take n _ | n <= 0 = []
take _ [] = []
take n (x : xs) = x : take (n - 1) xs
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f e [] = e
foldr f e (x : xs) = f x (foldr f e xs)
Siguiendo el mismo razonamiento que antes, intentamos reducir take
pero no podemos porque necesitaríamos un constructor en la parte más externa de la expresión del segundo argumento, y por ahora tenemos solo a
. Lo único que podemos empezar reduciendo es a
.
take 4 a
take 4 (1 : foldr (\x xs -> 1 + x : xs) [] a)
Ahora si estamos en condiciones de reducir take
usando la tercer ecuación.
take 4 a
take 4 (1 : foldr (\x xs -> 1 + x : xs) [] a)
1 : take (4 - 1) (foldr (\x xs -> 1 + x : xs) [] a)
Intentamos reducir take
nuevamente y nos va a llevar a reducir 4 - 1
para poder determinar si es <= 0
, lo que no se cumple. No podemos reducir take
porque en el segundo argumento no tenemos un constructor en la parte más externa.
Intentamos reducir foldr (\x xs -> 1 + x : xs) [] a
. Mirando la definición de foldr
vemos que para reducirla necesitamos un constructor en la parte más externa del tercer argumento, que en este caso es a
, por lo que tampoco podemos reducir foldr
. Lo siguiente a intentar reducir es a
que si puede reducirse.
take 4 a
take 4 (1 : foldr (\x xs -> 1 + x : xs) [] a)
1 : take (4 - 1) (foldr (\x xs -> 1 + x : xs) [] a)
1 : take 3 (foldr (\x xs -> 1 + x : xs) [] (1 : foldr (\x xs -> 1 + x : xs) [] a))
Ahora si podemos reducir el foldr
porque tenemos un :
en la parte más externa de su tercer argumento. Usamos la segunda ecuación.
Capaz que es un poco difícil de ver, por lo que hago este paso más despacio.
La expresión que estamos reduciendo en este paso es:
foldr (\x xs -> 1 + x : xs) [] (1 : foldr (\x xs -> 1 + x : xs) [] a)
y la ecuación que estamos en condiciones de usar de la definición de foldr
es esta:
foldr f e (x : xs) = f x (foldr f e xs)
Entonces tenemos:
(del lado izquierdo)
f = \x xs -> 1 + x : xs
e = []
x = 1
xs = foldr (\x xs -> 1 + x : xs) [] a
(del lado derecho)
foldr f e xs = foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a)
f x (foldr f e xs) = 1 + 1 : foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a)
Por lo que la expresión original se reduce en 1 + 1 : foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a)
.
take 4 a
take 4 (1 : foldr (\x xs -> 1 + x : xs) [] a)
1 : take (4 - 1) (foldr (\x xs -> 1 + x : xs) [] a)
1 : take 3 (foldr (\x xs -> 1 + x : xs) [] (1 : foldr (\x xs -> 1 + x : xs) [] a))
1 : take 3 (1 + 1 : foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a))
Ahora volvemos a estar en condiciones de reducir el take
que es la aplicación más externa.
take 4 a
take 4 (1 : foldr (\x xs -> 1 + x : xs) [] a)
1 : take (4 - 1) (foldr (\x xs -> 1 + x : xs) [] a)
1 : take 3 (foldr (\x xs -> 1 + x : xs) [] (1 : foldr (\x xs -> 1 + x : xs) [] a))
1 : take 3 (1 + 1 : foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a))
1 : 1 + 1 : take (3 - 1) (foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a))
Siguiendo los mismos razonamientos que antes, tenemos que reducir nuevamente a
.
take 4 a
take 4 (1 : foldr (\x xs -> 1 + x : xs) [] a)
1 : take (4 - 1) (foldr (\x xs -> 1 + x : xs) [] a)
1 : take 3 (foldr (\x xs -> 1 + x : xs) [] (1 : foldr (\x xs -> 1 + x : xs) [] a))
1 : take 3 (1 + 1 : foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a))
1 : 1 + 1 : take (3 - 1) (foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a))
1 : 1 + 1 : take 2 (foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] (1 : foldr (\x xs -> 1 + x : xs) [] a)))
Más allá de que la expresión queda complicada, el razonamiento que se sigue es el mismo que antes. Ahora estamos en condiciones de reducir foldr (\x xs -> 1 + x : xs) [] (1 : foldr (\x xs -> 1 + x : xs) [] a)
, que es la misma expresión que teníamos antes, podemos reutilizar la reducción anterior.
take 4 a
take 4 (1 : foldr (\x xs -> 1 + x : xs) [] a)
1 : take (4 - 1) (foldr (\x xs -> 1 + x : xs) [] a)
1 : take 3 (foldr (\x xs -> 1 + x : xs) [] (1 : foldr (\x xs -> 1 + x : xs) [] a))
1 : take 3 (1 + 1 : foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a))
1 : 1 + 1 : take (3 - 1) (foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a))
1 : 1 + 1 : take 2 (foldr (\x xs -> 1 + x : xs) [] (1 + 1 : foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a)))
El paso siguiente de la evaluación es reducir foldr (\x xs -> 1 + x : xs) [] (1 + 1 : foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a))
.
Comparado con la reducción que hicimos antes del foldr
, cambian quienes son
x
y xs
:
x = 1 + 1
xs = foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a)
Luego de aplicar el paso de reducción queda: 1 + 1 + 1 : foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a)
Integrando todo:
take 4 a
take 4 (1 : foldr (\x xs -> 1 + x : xs) [] a)
1 : take (4 - 1) (foldr (\x xs -> 1 + x : xs) [] a)
1 : take 3 (foldr (\x xs -> 1 + x : xs) [] (1 : foldr (\x xs -> 1 + x : xs) [] a))
1 : take 3 (1 + 1 : foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a))
1 : 1 + 1 : take (3 - 1) (foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a))
1 : 1 + 1 : take 2 (foldr (\x xs -> 1 + x : xs) [] (1 + 1 : foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a)))
1 : 1 + 1 : take 2 (1 + 1 + 1 : foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a))
Reduciendo take
tenemos:
take 4 a
take 4 (1 : foldr (\x xs -> 1 + x : xs) [] a)
1 : take (4 - 1) (foldr (\x xs -> 1 + x : xs) [] a)
1 : take 3 (foldr (\x xs -> 1 + x : xs) [] (1 : foldr (\x xs -> 1 + x : xs) [] a))
1 : take 3 (1 + 1 : foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a))
1 : 1 + 1 : take (3 - 1) (foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a))
1 : 1 + 1 : take 2 (foldr (\x xs -> 1 + x : xs) [] (1 + 1 : foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a)))
1 : 1 + 1 : take 2 (1 + 1 + 1 : foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a))
1 : 1 + 1 : 1 + 1 + 1 : take (2 - 1) (foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] (foldr (\x xs -> 1 + x : xs) [] a))
Como se puede ir viendo, la lista que se va produciendo suma uno al elemento anterior. Si continuás con los pasos de reducción vas a llegar a [1,2,3,4]
.