2009-06-28 5 views
11

Ich versuche clojure ich versuche, herauszufinden, wie man den folgenden Algorithmus zu implementieren,Clojure While-Schleife

ich von einem Eingangsstrom lese ich das Lese fortsetzen will, bis es kein Begrenzungszeichen ist.

Ich kann dies in Java mit einer while-Schleife tun, aber ich kann nicht scheinen, wie es in clojure zu tun?

 
while 
    read 
    readChar != delimiter 

    do some processing.... 
end while 

Antwort

10

Ich weiß nicht, Clojure, aber es sieht, dass, wie Schema, es unterstützt "lassen Schleifen":

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

Hope this genug ist, um Ihnen den Einstieg. Ich habe auf http://clojure.org/special_forms#toc9 verwiesen, um diese Frage zu beantworten.

HINWEIS: Ich weiß, dass Clojure von Nebenwirkungen abhält, also möchten Sie vermutlich etwas Nützliches anstelle von '() zurückgeben.

+0

Richtig über den Nebeneffekt. Vielleicht fügen Sie der Schleife einen Akkumulator hinzu, um zu zeigen, wie ein Ergebnis funktional aufgebaut ist? –

2

Ich kam dies im Geiste der line-seq. Es ist völlig faul und zeigt mehr von Clojures funktionaler Natur als 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

Muss ein kürzerer Weg sein, dies zu tun. – Kzqai

1

Eine while-Schleife beinhaltet normalerweise veränderbare Variablen, d. H. Warten, bis eine Variable eine bestimmte Bedingung erfüllt; in Clojure würden Sie normalerweise Tail-Recursion verwenden (was der Compiler in eine while-Schleife übersetzt) ​​

Das Folgende ist keine richtige Lösung, aber diese Variante der for-Schleife könnte in einigen Fällen hilfreich sein:

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

Dadurch wird eine Liste aller Paare von a und b bis(< (* a b) 1000) erstellen. Das heißt, es wird aufhören, sobald die Bedingung erfüllt ist. Wenn Sie ersetzen: während mit: wenn, können Sie alle der Paare finden, die die Bedingung erfüllen, auch nachdem es eines findet, das nicht tut.

5

Arbeiten an Clojure 1.3.0, und für das, was es wert ist, können Sie schreiben, während Schleifen in Clojure nun so etwas wie

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

dies beruht auf einigen Nebenwirkungen, damit der Wahrheitsausdruck schließlich falsch wird. – tenpn

3

Der Loop Ansatz tun wird in clojure jedoch Schleife/recur gut funktionieren sind betrachtete Operationen auf niedriger Ebene und Funktionen höherer Ordnung gewöhnlich bevorzugt.

Normalerweise würde diese Art von Problem durch die Schaffung einer Folge von Token (Zeichen in Ihrem Beispiel) und die Anwendung auf oder mehreren der clojure der Folgefunktionen (doseq, dorun, Take-Zeit, etc.)

Die gelöst werden Im folgenden Beispiel wird der erste Benutzername von/etc/passwd auf Unix-ähnlichen Systemen gelesen.

(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

Ich kam mit dieser Version aus:

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

Es für einen String sieht, nicht ein einzelnes Zeichen als Trennzeichen!

Danke!