Какой смысл в лени-сэке в clojure?
Я просматриваю пример кода последовательности Фибоначчи:
(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, потому что у меня была предыдущая привязка к выдумкам в области видимости.
2 ответа
lazy-seq
на [1 2]
не нужно, но на самом деле не больно.
lazy-seq
на (map + fibs (rest fibs))
необходимо; без него вызов функции будет оценен до fibs
привязан к значению, которое вызовет исключение. Заворачивая это в lazy-seq
вызов будет отложен до получения значения, и fibs
будет иметь значение в этой точке.
Насколько я понимаю (и я признаю, что все еще являюсь относительным новичком в Clojure!), Если вы попробуете следующее:
(def fibs (concat [1 2] (map + fibs (rest fibs))))
Тогда это не сработает, потому что выдумки еще не связаны, и поэтому две более поздние ссылки на него терпят неудачу.
Однако ленивая версия, которую вы дадите, будет работать, потому что ссылки на FIB-ы на самом деле разрешаются только в более позднее время, когда используется последовательность - и к этому моменту FIB-ы уже были успешно определены как Lazy-последовательность.