2009-06-28 53 views
11

我想的Clojure我試圖找出如何實現以下算法,Clojure的While循環

我從我想繼續讀書,直到它不是一個分隔符的輸入流中讀取。

我可以在java中用while循環做到這一點,但我似乎無法弄清楚如何在clojure中做到這一點?

 
while 
    read 
    readChar != delimiter 

    do some processing.... 
end while 

回答

10

我不知道的Clojure,但看起來,像方案,它支持「讓循環」:

(loop [char (readChar)] 
    (if (= char delimiter) 
     '() 
     (do (some-processing) 
      (recur (readChar))))) 

希望這是足以讓你開始。我提到http://clojure.org/special_forms#toc9回答這個問題。

注:我知道Clojure不鼓勵副作用,所以大概你想返回一些有用的東西而不是'()。

+0

正確的副作用。也許可以在循環中添加一個累加器來顯示如何在功能上構建結果? – 2011-02-19 09:12:47

2

我想出了line-seq這個精神。這完全是懶惰的,展現出更多的Clojure的功能性,比loop

(defn delim-seq 
    ([#^java.io.Reader rdr #^Character delim] 
    (delim-seq rdr delim (StringBuilder.))) 
    ([#^java.io.Reader rdr #^Character delim #^StringBuilder buf] 
    (lazy-seq 
     (let [ch (.read rdr)] 
     (when-not (= ch -1) 
      (if (= (char ch) delim) 
      (cons (str buf) (delim-seq rdr delim)) 
      (delim-seq rdr delim (doto buf (.append (char ch)))))))))) 

Full paste

+0

得到一個更短的方式'ta做到這一點。 – Kzqai 2010-01-09 19:46:56

1

while循環通常涉及可變變量,即等到變量滿足特定條件; Clojure中你通常用尾遞歸(編譯器轉換成一個while循環)

以下是不完全的解決方案,但for循環的這種變化可能會在某些情況下會有所幫助:

(for [a (range 100) 
     b (range 100) 
     :while (< (* a b) 1000)] 
    [a b] 
) 

這將創建所有對a和b 的列表,直到(< (* a b) 1000)。只要條件得到滿足,它就會停止。如果你更換:while with:when,他們可以找到全部滿足條件的對,即使它找到了一個沒有的條件。

5

上的Clojure 1.3.0工作,併爲它的價值,你可以寫,而用Clojure循環,現在通過做一些類似於

(while truth-expression 
    (call-some-function)) 
+0

這依靠一些副作用來使真相表達式最終變成假。 – tenpn 2016-01-25 09:51:55

3

循環方法將用Clojure但環/易復發做工精細是考慮低級操作和高級功能通常是首選。

通常這類問題會通過創建令牌的序列來解決(在你的例子字符)和應用或更多的Clojure的序列功能(doseq,dorun,採取-while等)

的以下示例從unix類似系統上的/ etc/passwd中讀取第一個用戶名。

(require '[clojure.java [io :as io]]) 

(defn char-seq 
    "create a lazy sequence of characters from an input stream" 
    [i-stream] 
    (map char 
    (take-while 
    (partial not= -1) 
    (repeatedly #(.read i-stream))))) 

;; process the sequence one token at a time 
;; with-open will automatically close the stream for us 

(with-open [is (io/input-stream "/etc/passwd")] 
    (doseq [c (take-while (partial not= \:) (char-seq is))] 
    ;; your processing is done here 
    (prn c))) 
0

我想出了這個版本:

(defn read-until 
    [^java.io.Reader rdr ^String delim] 
    (let [^java.lang.StringBuilder salida (StringBuilder.) ] 
    (while 
     (not (.endsWith (.toString salida) delim)) 
     (.append salida (str (char (.read rdr)))) 
    ) 
    (.toString salida) 
) 
) 

它尋找一個字符串,而不是單個字符作爲分隔符!

謝謝!