【问题标题】:Clojure lazy-eval inside applyClojure惰性评估内部应用
【发布时间】:2013-10-10 15:13:52
【问题描述】:

我正在尝试逐行读取文件并将新字符串连接到每行的末尾。为了测试我已经这样做了:

(defn read-file
[filename]
(with-open [rdr (clojure.java.io/reader filename)]
  (doall (line-seq rdr))))

(apply str ["asdfasdf" (doall (take 1 (read-file filename)))])

如果我只是在 repl 中评估 (take 1 (read-file filename)),我会得到文件的第一行。但是,当我尝试评估我在上面所做的事情时,我得到了"asdfasdfclojure.lang.LazySeq@4be5d1db"

谁能解释如何强制评估 take 以使其不返回惰性序列?

【问题讨论】:

    标签: clojure eval lazy-evaluation take


    【解决方案1】:

    take 函数在设计上是惰性的,因此您可能必须使用firstnextnth 来实现您想要的值,或者使用apply 等函数对整个序列进行操作、reducevecinto

    在您的情况下,您似乎正在尝试执行以下操作:

    (apply str ["asdfasdf" (apply str (take 1 (read-file filename)))])
    

    或者:

    (str "asdfasdf" (first (read-file filename)))
    


    你也可以使用doall 实现整个lazyseq。请记住,实现的惰性序列仍然是序列。

    (realized? (take 1 (read-file filename))) ;; => false
    (type (take 1 (read-file filename))) ;; => clojure.lang.LazySeq
    
    (realized? (doall (take 1 (read-file filename)))) ;; => true
    (type (doall (take 1 (read-file filename)))) ;; => clojure.lang.LazySeq
    


    一个更好的选择是懒惰地应用你的转换,使用类似map的东西,然后从结果序列中选择你想要的值。 (如流处理。)

    (first (map #(str "prefix" % "suffix")
                 (read-file filename)))
    

    注意:map 是惰性的,所以它会返回一个未实现的 LazySeq。

    【讨论】:

    • 这行得通,谢谢。不过我不得不问,doall 的文档字符串说它强制对函数进行惰性求值,但是,当我这样做 (apply str ["asdfasdf" (doall (take 1 (read-file filename)))]) 时,我仍然会得到lazyseq。你能解释一下吗?
    • 一个lazyseq不需要转换成其他类型就可以实现。 doall 实现了整个 seq,但你还是要把它当作一个 seq 来对待。
    • 谢谢你把事情弄清楚了,我以为是这样的,但我认为理解 clojure 的文档字符串本身就是一种天赋:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-08
    • 2013-03-11
    • 2017-01-18
    • 2018-11-11
    • 2011-06-05
    相关资源
    最近更新 更多