2009-06-28 6 views
11

私はClojureの私は、次のアルゴリズムを実装する方法を把握しようとしていますをしようと、Clojureのループ

私はそれが区切り文字でなくなるまで読み続けたい入力ストリームから読んでいながら。

私はwhileループでjavaでこれを行うことができますが、私は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

右の副作用について。おそらく、アキュムレータをループに追加して、結果が機能的にどのように構築されているかを示しますか? –

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

これを行うには、もっと短い方法が必要です。 – Kzqai

1

whileループには通常可変変数が含まれます。つまり、変数が特定の条件を満たすまで待機します。 Clojureでは通常tail-recursionを使用します(コンパイラはwhileループに変換します)

次のような解決策はありませんが、forループのこのバリエーションは場合によっては助けになることがあります。

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

これは(< (* a b) 1000)まで、すべてのペアとB のリストを作成します。つまり、条件が満たされるとすぐに停止します。 :while:with:を置き換えると、のすべてのが条件を満たすペアのうち見つからない場合でも見つけることができます。

5

Clojureの1.3.0に取り組んで、そして何が価値がある今

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

これは真実表現を最終的に偽にするためのいくつかの副作用に依存しています。 – tenpn

3

ループアプローチに似て何かをすることによって、Clojureの中のループがClojureのがループ/ RECURで正常に動作しますが、あなたは書くことができるため低レベル動作と考えられ、高次機能が通常好ましい。

通常、この種の問題は、トークン(あなたの例では文字)の配列を作成し、上の適用によって解決やClojureののシーケンス機能(doseq、dorun、テイクしばらく、など)の多くのことになる

次の例では、システムのような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) 
) 
) 

それは文字列ではなく、区切り文字として単一の文字を探します!

ありがとうございます!