Почему line-seq возвращает clojure.lang.Cons вместо clojure.lang.LazySeq?

Согласно записи ClojureDocs для line-seq (http://clojuredocs.org/clojure_core/clojure.core/line-seq) и принятый ответ на вопрос о стеке (В Clojure 1.3, Как читать и писать файл) line-seq должен возвращать отложенный seq при передаче java.io.BufferedReader.

Однако, когда я тестирую это в REPL, тип отображается как clojure.lang.Cons. См. Код ниже:

=> (ns stack-question
     (:require [clojure.java.io :as io]))
nil
=> (type (line-seq (io/reader "test-file.txt")))
clojure.lang.Cons
=> (type (lazy-seq (line-seq (io/reader "test-file.txt"))))
clojure.lang.LazySeq

Завершение вызова line-seq вызовом lazy-seq дает ленивый seq, но, согласно документации, в этом нет необходимости: line-seq в любом случае должен возвращать lazy seq.

Примечание. Внутри REPL (я использую nrepl) кажется, что ленивые последовательности полностью реализованы, поэтому я подумал, что, возможно, это просто причуда REPL; однако та же проблема возникает, когда я тестирую его с помощью Speclj. Кроме того, я не думаю, что осознание того, что ленивый seq все равно имеет отношение к тому, что происходит.

РЕДАКТИРОВАТЬ: Итак, я пошел проверить исходный код после того, как ответ mobyte сказал, что в хвосте минусов есть ленивый seq ...

1   (defn line-seq
2     "Returns the lines of text from rdr as a lazy sequence of strings.
3     rdr must implement java.io.BufferedReader."
4     {:added "1.0"}
5     [^java.io.BufferedReader rdr]
6     (when-let [line (.readLine rdr)]
7       (cons line (lazy-seq (line-seq rdr)))))

Этот вызов cons объясняет, почему тип возвращаемого значения line-seq - clojure.lang.Cons.


person Community    schedule 03.03.2013    source источник


Ответы (1)


Вам не нужен вывод "wrap" Cons, потому что он уже имеет lazy seq как "tail":

(type (line-seq (io/reader "test-file.txt")))
=> clojure.lang.Cons

(type (rest (line-seq (io/reader "test-file.txt"))))
=> clojure.lang.LazySeq

(type (cons 'a (rest (line-seq (io/reader "test-file.txt")))))
=> clojure.lang.Cons

Изменить.

Примечание: внутри REPL (я использую nrepl) кажется, что ленивые последовательности полностью реализованы

Не верно. Вы можете проверить это:

(with-open [r (io/reader "test-file.txt")] (line-seq r))
=> IOException Stream closed  java.io.BufferedReader.ensureOpen (BufferedReader.java:97)

Это потому, что line-seq возвращает lazy-seq, что не полностью реализовано, и reader уже закрыт, когда repl пытается реализовать результат позже, чтобы распечатать его. Но если вы осознаете это явно, это даст нормальный результат без каких-либо исключений:

(with-open [r (io/reader "/home/mobyte/2")] (doall (line-seq r)))
=> ...  output ...
person mobyte    schedule 03.03.2013
comment
Итак, я полагаю, что ввод (line-seq my-buffered-reader) в REPL и его полная распечатка означает, что ленивый seq оценивается только для шага печати, но не на самом деле до этого момента? - person ; 03.03.2013