Я изучаю Haskell и следующее выражение на Haskell Wiki
действительно озадачил меня:
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
Я не могу понять, почему это работает.
Если я применяю стандартную логику каррирования (zipWith (+))
возвращает функцию, принимает список в качестве аргумента и, в свою очередь, возвращает другую функцию, которая принимает другой список в качестве аргумента и возвращает список (zipWith::(a -> b -> c) -> [a] -> [b] -> [c]
). Таким образом, fibs
является ссылкой на список (который еще не был оценен), а (tail fibs)
является хвостом того же (неоцененного) списка. Когда мы пытаемся оценить (take 10 fibs
), первые два элемента привязываются к 0
и 1
. Другими словами fibs==[0,1,?,?...]
и (tail fibs)==[1,?,?,?]
. После завершения первого добавления fibs
становится [0,1,0+1,?,..]
. Аналогично, после второго добавления получаем [0,1,0+1,1+(0+1),?,?..]
- Правильна ли моя логика?
- Есть ли более простой способ объяснить это? (какие-либо идеи от людей, которые знают, что делает компилятор Haskell с этим кодом?) (ссылки и ссылки приветствуются)
- Это правда, что этот тип кода работает только из-за ленивой оценки?
- Какие оценки происходят, когда я делаю
fibs !! 4
?
- Предполагается ли в этом коде, что zipWith обрабатывает элементы от первого до последнего? (Я думаю, что это не должно, но я не понимаю, почему нет)
РЕДАКТИРОВАТЬ2: Я только что нашел вопрос, заданный выше и хорошо ответил здесь Прошу прощения, если я впустую потратил время
РЕДАКТИРОВАТЬ: здесь более сложный для понимания случай (источник: Project Euler форумы ):
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) ]
Обратите внимание, что all (\y -> x mod y /= 0)...
Как ссылка на x здесь НЕ может вызвать бесконечную рекурсию?