Давайте, что он также работает с одним cons
снаружи:
(def fibs (cons 0 (lazy-seq (cons 1 (map + fibs (rest fibs))))))
Давайте также установить, что lazy-seq
макрос (очевидно, так как он не оценивает аргументы) и помещает body
(аргумент (s) до lazy-seq
) в функцию.
Теперь, если вы «запросите» элемент из этой последовательности, эта функция вызывается один раз, а последующие вызовы возвращают кешированное значение.
Очевидно, что только после того, как функция возвращает что-то, у вас есть доступное значение. Теперь, что происходит в нашем плохом случае:
Представьте, что clojure находится в середине оценки функции в первый раз. Первое, что ему нужно, это +
, fibs
и (rest fibs)
, чтобы передать это минусам. Теперь clojure увидит, что fibs
является ленивой последовательностью и вызывает его! Это потому, что вы в настоящий момент находитесь в своем первом вызове и не возвращаетесь. Это вызывает бесконечную рекурсию.
Исправить легко: убедитесь, что в начале списка есть реализованный элемент, чтобы два выражения, fibs
и (rest fibs
) могли что-то вернуть. В частности, взятие rest
из (cons 1 whatever)
вернет whatever
without realizing a single element (важно, поскольку в противном случае у нас была бы такая же проблема снова).
Что вы пытаетесь достичь с помощью 'lazy-seq'? Кажется, это нормально, если вы просто удалите его. – jmargolisvt
@jmargolisvt На мой repl (clojure 1.6) код '(def fibs (cons 0 (cons 1 (map + fibs (rest fibs)))))' не работает. Lazy-seq необходимо, я думаю, потому что он задерживает вычисление потока, иначе он не будет работать с определением fibs в терминах самих фибо – Matteo