Это было очень информативно. Спасибо!
аюсь понять Clojure'slazy-seq
оператор, и концепция ленивых оценки в целом. Мне известна основная идея, лежащая в основе концепции: оценка выражения откладывается до тех пор, пока не потребуется значение.
В общем, это достижимо двумя способами:
во время компиляции с использованием макросов или специальных форм;во время выполнения с использованием лямбда-функцийИспользуя ленивые методы оценки, можно создавать бесконечные структуры данных, которые оцениваются как используемые. Эти бесконечные последовательности используют лямбды, замыкания и рекурсию. В ближайшем будущем, эти бесконечные структуры данных генерируются с использованиемlazy-seq
а такжеcons
формы.
Я хочу понять какlazy-seq
это волшебство Я знаю, что это на самом деле макрос. Рассмотрим следующий пример.
(defn rep [n]
(lazy-seq (cons n (rep n))))
Здесьrep
функция возвращает лениво вычисленную последовательность типаLazySeq
, который теперь может быть преобразован и потреблен (таким образом оценен), используя API последовательности. Этот API предоставляет функцииtake
, map
, filter
а такжеreduce
.
В развернутом виде мы можем увидеть, как лямбда используется для хранения рецепта для ячейки без его немедленной оценки.
(defn rep [n]
(new clojure.lang.LazySeq (fn* [] (cons n (rep n)))))
Нокак на самом деле работает API последовательностиLazySeq
?Что на самом деле происходит в следующем выражении?(reduce + (take 3 (map inc (rep 5))))
map
применяется к последовательности,какtake
ограничить последовательность а такжекак работает терминалreduce
оценить последовательность?Также,как эти функции работают сVector
илиLazySeq
?
Также,Можно ли создавать вложенные бесконечные структуры данных?: список, содержащий списки, содержащие списки, содержащие списки ... идущие бесконечно широко и глубоко, оцениваемые как используемые с помощью API последовательности?
И последний вопрос,есть ли практическая разница между этим
(defn rep [n]
(lazy-seq (cons n (rep n))))
и это?
(defn rep [n]
(cons n (lazy-seq (rep n))))