2013-10-10 55 views
0

我試圖逐行閱讀文件並將新字符串連接到每行的末尾。爲了測試我已經做到了這一點:Clojure lazy-eval內部應用

(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)),我得到的文件的第一行。但是,當我嘗試評估我上面做的時,我得到了"[email protected]"

任何人都可以解釋如何強制評估take讓它不返回懶惰序列?

回答

1

take功能是通過設計懶惰,所以你可能要實現你想要的值,使用firstnext,或nth,或者對整個序列與功能,如applyreducevec,或into操作。

在你的情況下,它看起來像你正在嘗試做以下:

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

或者:

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


你也可以體會到使用doall整個lazyseq。請記住,實現的懶惰seq仍然是一個seq。

(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。

+0

工作,謝謝。我必須問,doall的文檔字符串表示強制函數的懶惰評估,但是,當我做'(應用str [「asdfasdf」(doall(take 1(read-file filename)))])'我仍然得到懶惰。你能解釋一下嗎? – Nick

+0

lazyseq可以在不轉換爲其他類型的情況下實現。 'doall'實現了整個seq,但你仍然必須像seq那樣對待它。 – Jared314

+0

謝謝,清除了一些東西,我在想這是這樣的,但理解clojure的文檔是天才,本身我認爲:) – Nick