Hay varias formas equivalentes de entenderlo.Primero: foldr f z [1, 2, 3, 4, ..., n]
calcula el siguiente valor:
f 1 (f 2 (f 3 (f 4 (f ... (f n z)))))
Así, en su caso:
length [1,2,3,4] = foldr (\_ n -> 1 + n) 0 [1,2,3,4]
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 ((\_ n -> 1 + n) 3 ((\_ n -> 1 + n) 4 0)))
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 ((\_ n -> 1 + n) 3 (1 + 0)))
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 (1 + (1 + 0)))
= (\_ n -> 1 + n) 1 (1 + (1 + (1 + 0)))
= 1 + (1 + (1 + (1 + 0)))
= 1 + (1 + (1 + 1))
= 1 + (1 + 2)
= 1 + 3
= 4
Otra es que partir de esta función, que copia una lista:
listCopy :: [a] -> [a]
listCopy [] = []
listCopy (x:xs) = x : listCopy xs
Eso puede parecer una función trivial, pero foldr
es básicamente eso, pero excepto el código duro de la lista vacía []
y el constructor de pares :
en el lado derecho, en su lugar usamos algunas constantes y funciones arbitrarias proporcionadas como argumentos. A veces me gusta llamar a estos argumentos fakeCons
y fakeNil
(cons
y nil
son los nombres de operador :
y []
constante en el lenguaje Lisp), porque en un sentido que está "copia" la lista, pero el uso de constructores falsos:
foldr fakeCons fakeNil [] = fakeNil
foldr fakeCons fakeNil (x:xs) = fakeCons x (subfold xs)
where subfold = foldr fakeCons fakeNil
Así, bajo esta interpretación, su función es length
"copia" de una lista, excepto que en lugar de la lista vacía se trata de utilizar 0
, y en vez de :
es descartando los elementos y sumando 1 al total acumulado.
Y aquí es todavía una tercera INTERPRETACIÓN de foldr f z xs
:
z
es la solución de su problema cuando la lista está vacía.
f
es una función que toma dos argumentos: un elemento de la lista, y una solución parcial: la solución a su problema de la lista de elementos que aparecen a la derecha del elemento que se pasa a f
. f
produce una solución que es "un elemento más grande".
Así, en el caso de length
:
- La longitud de una lista vacía es 0, así que por eso se utiliza 0 como segundo argumento a
foldr
.
- Si la longitud de
xs
es n
, entonces la longitud de x:xs
es n+1
. Eso es lo que está haciendo su primer argumento al foldr
, \_ n -> n + 1
: está calculando la longitud de una lista, dado como argumentos el primer elemento de la lista (que en este caso ignoramos) y la longitud del resto de la lista (n
) .
Esta manera de pensar acerca de foldr
es muy poderosa, y no debe subestimarse. Básicamente, en la función que pasa como el primer argumento en foldr
, puede suponer que el problema que está tratando de resolver ya se ha resuelto para todas las listas más cortas que la que está tratando. Toda su función de argumento tiene que hacer, entonces, es calcular una respuesta para una lista que es un elemento más larga.
ver http://stackoverflow.com/questions/7704960/how-to-write-a-length-function-using-foldr-in-haskell para empezar. –
Ver también: http: // learnyouahaskell.com/higher-order-functions # fold –
Sería mejor si usa 'foldl'', que es bueno para su stack ' length = foldl '(\ n _ -> n + 1) 0' – Ronson