Нет, у Clojure нет ленивых карт.
Кроме того, если вы создаете последовательность, используя loop / recur, я не верю, что попытка сделать ее ленивой приводит к чему-либо (если генерация каждого элемента не медленная).
Посмотрите на эти две функции:
(defn bad-lazy-range [begin end]
(loop [i (dec end) lst nil]
(if (>= i begin)
(recur (dec i) (lazy-seq (cons i lst)))
lst)))
(defn good-lazy-range [begin end]
(if (>= begin end)
nil
(lazy-seq (cons begin (good-lazy-range (inc begin) end)))))
bad-lazy-range
будет повторяться begin-end
раз, генерируя thunk (ленивая ссылка последовательности) каждый раз, а затем возвращать самый внешний thunk. Этот блок должен содержать ссылку на следующий блок, который требует ссылку на третий блок и т. Д. Вы выполняете всю работу немедленно и генерируете псевдосвязанный список блоков, который занимает больше места, чем обычный список.
good-lazy-range
, однако, немедленно возвращается без повторения больше - рекурсивный вызов скрыт внутри thunk и не будет оцениваться до тех пор, пока не будет необходим. Это также предотвращает исключение переполнения стека - без вызова lazy-seq
это может сгенерировать исключение переполнения стека, но на каждом шаге он оценивает один вызов good-lazy-range
и возвращает. Затем вызывающий абонент может оценить следующий вызов, но на этом этапе кадр стека от первого вызова давно пропал.
В общем, используйте lazy-seq
, только если вы можете обернуть его вокруг значительного объема вычислений. В первой функции она заключена только в вызов cons
, который в любом случае быстро вернется. Однако во второй функции она обернута вокруг вызова cons
и рекурсивного вызова, что означает, что она задерживает стоящее количество вычислений.
Если ваш код использует ленивость правильно и использует loop / recur, пожалуйста, опубликуйте его - мне было бы интересно посмотреть, как вы это сделали.