estoy aprendiendo Haskell y que la siguiente expresión en Haskell Wiki realmente me desconcertado:autorreferencia en Haskell funciona
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
Estoy totalmente no puede entender por qué esto funciona.
Si aplico la lógica de currying estándar (zipWith (+))
devuelve una lista de tomas de función como argumento y, a su vez, devuelve otra función que toma otra lista como argumento y devuelve una lista (zipWith::(a -> b -> c) -> [a] -> [b] -> [c]
). Por lo tanto, fibs
es una referencia a una lista (que aún no se ha evaluado) y (tail fibs)
es la cola de la misma lista (no evaluada). Cuando intentamos evaluar (take 10 fibs
), los primeros dos elementos están vinculados a 0
y 1
. En otras palabras, fibs==[0,1,?,?...]
y (tail fibs)==[1,?,?,?]
. Después de que la primera adición completa fibs
se convierte en [0,1,0+1,?,..]
. Del mismo modo, después de la segunda adición obtenemos [0,1,0+1,1+(0+1),?,?..]
- ¿Mi lógica es correcta?
- ¿Hay un más simple manera de explicar esto? (¿Alguna idea de las personas que saben qué hace el compilador Haskell con este código?) (se aceptan enlaces y referencias)
- Es cierto que este tipo de código solo funciona debido a la evaluación perezosa?
- ¿Qué evaluaciones ocurren cuando hago
fibs !! 4
? - ¿Este código asume que zipWith procesa elementos de principio a fin? (Creo que no debería, pero no entiendo por qué no)
Edit2: acabo de encontrar la pregunta anterior preguntó y respondió bien here. Lo siento si desperdicié el tiempo de alguien.
EDIT: He aquí un caso más difícil de entender (fuente: Project Euler forums):
filterAbort :: (a -> Bool) -> [a] -> [a]
filterAbort p (x:xs) = if p x then x : filterAbort p xs else []
main :: Int
main = primelist !! 10000
where primelist = 2 : 3 : 5 : [ x | x <- [7..], odd x, all (\y -> x `mod` y /= 0) (filterAbort (<= (ceiling (sqrt (fromIntegral x)))) primelist) ]
Tenga en cuenta que all (\y -> x mod y /= 0)...
¿Cómo puede referirse a x aquí no causar una recursión infinita?
Eso parece correcto. También me parece simple: a medida que trabajes más con Haskell, tu cerebro comenzará a percibir estos patrones y te parecerá simple también. Buen comienzo. – luqui
Primero, 'filterAbort' es lo mismo que' takeWhile'. En segundo lugar, puede evitar los números pares escribiendo '[7,9 ..]'. En tercer lugar, no es necesario tener '5' en su lista inicial si usa' [5,7 ..] '. Y, por último, la razón por la que esto funciona es bastante profundo. Es porque para cada primo 'p' hay otro primo antes de' p^2'. Es una consecuencia trivial de un teorema de Lindemann (un primo entre p y 2p). – augustss
Gracias, augusto. Las optimizaciones y la limpieza que sugiere tienen sentido. En cuanto a la terminación, ¿podría dar más detalles? ¿A qué está obligado 'x 'en' (\ y -> x mod y/= 0) '? Sospecho que mi error es pensar que está ligado a una lista infinita. Si está ligado a un solo valor (digamos, '7') entonces no hay problema. ¿Puedes confirmar? –