Какой смысл в лени-сэке в clojure? - PullRequest
17 голосов
/ 31 мая 2010

Я просматриваю пример кода замыкания последовательности Фибоначчи:

 (def fibs (lazy-cat [1 2] (map + fibs (rest fibs))))

Я обычно понимаю, что происходит, но не понимаю, lazy-cat. Я знаю, что lazy-cat - это макрос, который переводит что-то вроде этого:

(def fibs (concat (lazy-seq [1 2]) (lazy-seq (map + fibs (rest fibs))))) 

Что именно lazy-seq выполняет? Это все равно будет оцениваться лениво даже без lazy-seq? Это строго для целей кэширования?

РЕДАКТИРОВАТЬ: Спасибо за ответы. Моя путаница заключалась в том, что он работал с простым concat из REPL, потому что у меня была предыдущая привязка к fibs в области действия.

Ответы [ 2 ]

16 голосов
/ 31 мая 2010

lazy-seq на [1 2] не требуется, но на самом деле не больно.

lazy-seq на (map + fibs (rest fibs)) имеет важное значение; без него вызов функции будет оцениваться до того, как fibs будет привязано к значению, что вызовет исключение. Обернув его в lazy-seq, вызов будет отложен до тех пор, пока не понадобится значение, и fibs будет иметь значение в этой точке.

7 голосов
/ 31 мая 2010

Насколько я понимаю (и я признаю, что все еще являюсь относительным новичком в Clojure!), Если вы попробуете следующее:

(def fibs (concat [1 2] (map + fibs (rest fibs))))

Тогда это не сработает, потому что выдумки еще не связаны, и поэтому две более поздние ссылки на него терпят неудачу.

Однако ленивая версия, которую вы дадите, будет работать, потому что ссылки на fibs фактически разрешаются только в более позднее время, когда используется последовательность - и к этому моменту fibs уже были успешно определены как отложенная последовательность.

...