为什么line-seq会返回clojure.lang.Cons而不是clojure.lang.LazySeq?

7 file-io clojure cons lazy-sequences

根据line-seq的ClojureDocs条目(http://clojuredocs.org/clojure_core/clojure.core/line-seq)和Stack问题的接受答案(在Clojure 1.3中,如何读取和写入文件), line-seq在传递java.io.BufferedReader时应该返回一个lazy seq.

但是当我在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
Run Code Online (Sandbox Code Playgroud)

在lazy-seq调用中包含line-seq调用会给出一个懒惰的seq,但根据文档,这不是必需的:line-seq应该返回一个懒惰的seq.

注意:在REPL里面(我正在使用nrepl)似乎懒惰的seqs完全实现了,所以我想也许这只是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)))))
Run Code Online (Sandbox Code Playgroud)

对cons的调用将解释为什么line-seq的返回值的类型是clojure.lang.Cons.

mob*_*yte 3

您不需要“wrap”输出,Cons因为它已经将惰性序列作为“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
Run Code Online (Sandbox Code Playgroud)

编辑。

注意:在 REPL 内部(我正在使用 nrepl),似乎惰性 seq 得到了完全实现

不正确。你可以测试一下:

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

这是因为当 repl 尝试稍后实现结果以打印它时,line-seq返回lazy-seq尚未完全实现并且reader已经关闭。但如果你明确地意识到它会给出正常的结果,没有任何异常:

(with-open [r (io/reader "/home/mobyte/2")] (doall (line-seq r)))
=> ...  output ...
Run Code Online (Sandbox Code Playgroud)