Я нарисовал изображение, которое может показаться вам полезным.
Обратите внимание, что zipWtih op (x:xs) (y:xs) = (op x y):zipWith xs ys
, то есть как zipWtih
появляется, чтобы «двигаться» прямо по списку. Он читает элементы и выплевывая суммы:
Вот более подробная оценка шаг за шагом. (Хотя я буду вставлять копии того, что там, в памяти есть только одна копия.) Я буду использовать ....
для вещей, которые я не могу беспокоить, чтобы их выписать.
fib = 0:1:zipWith (+) fib (tail fib)
= 0:1:zipWith (+) (0:1: ....) (tail (0:1: ....)
= 0:1:(0+1:zipWith (+) (1:(0+1: ....)) (0+1:.....))
= 0:1:1:zipWith (+) (1: ....) (......)
Обратите внимание, что теперь мы знаем, что zipWith (+) fib (tail fib) = 1:.....
.
= 0:1:1:zipWith (+) (1:1: ....) (1:......)
= 0:1:1:(1+1):zipWith (+) (1:(1+1): .....) ((1+1):....)
= 0:1:1:2:zipWith (+) (1:2: .....) (2:....)
Я пойду немного быстрее:
= 0:1:1:2:(1+2):zipWith (+) (2: .....) (....)
= 0:1:1:2:3 :zipWith (+) (2:3 .....) (3:....)
= 0:1:1:2:3:(2+3):zipWith (+) (3:(2+3):.....) ((2+3):.....)
= 0:1:1:2:3:5 :zipWith (+) (3:5:.....) (5:.....)
= 0:1:1:2:3:5:8 :zipWith (+) (5:8:....) (8:......)
= 0:1:1:2:3:5:8:13 :zipWith (+) (8:13:....) (13:......)
= 0:1:1:2:3:5:8:13:21:zipWith (+) (13:21....) (21:......)
На каждом этапе, последние два аргумента функции zipWith
, как указатели на (одну и две позиции) дальше вверх по fib
списка, чем мы в настоящее время.
В двух словах * ленивое программирование *. –