2009-06-28 14 views
11

io cercando clojure sto cercando di capire come implementare il seguente algoritmo,Clojure While Loop

Sto leggendo da un flusso di input che voglio continuare a leggere fino a quando non è un carattere delimitatore.

posso farlo in java con un ciclo while ma non riesco a capire come farlo in clojure?

 
while 
    read 
    readChar != delimiter 

    do some processing.... 
end while 

risposta

10

non so Clojure, ma sembra che, come Scheme, supporta "lascia loop":

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

Spero che questo è sufficiente per iniziare. Mi sono riferito a http://clojure.org/special_forms#toc9 per rispondere a questa domanda.

NOTA: So che Clojure scoraggia gli effetti collaterali, quindi presumibilmente si desidera restituire qualcosa di utile invece di '().

+0

Proprio sull'effetto collaterale. Forse aggiungere un accumulatore al ciclo per mostrare come un risultato è costruito funzionalmente? –

2

Mi sono inventato nello spirito di line-seq. È completamente pigro e mostra più natura funzionale di Clojure di 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

Devi essere un modo più breve 'fai questo. – Kzqai

1

Un ciclo while di solito comporta variabili mutabili, ovvero attendere che una variabile soddisfi una determinata condizione; in Clojure di solito usi la ricorsione in coda (che il compilatore traduce in un ciclo while)

Quanto segue non è una soluzione, ma questa variazione del ciclo for potrebbe essere di aiuto in alcuni casi:

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

Ciò creerà un elenco di tutte le coppie di ae b fino(< (* a b) 1000). Cioè si fermerà non appena la condizione è soddisfatta. Se sostituisci: mentre con: quando, loro possono trovare tutti i delle coppie che soddisfano la condizione, anche dopo che ne trova uno che non lo fa.

5

Lavorando su Clojure 1.3.0, e per quel che vale, è possibile scrivere cicli while in Clojure ora di fare qualcosa di simile a

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

questo si basa su alcuni effetti collaterali per rendere l'espressione della verità alla fine falsa. – tenpn

3

L'approccio ciclo funzionerà benissimo in clojure tuttavia loop/ricorrono sono considerate le operazioni a basso livello e le funzioni di ordine superiore generalmente preferite.

Normalmente questo tipo di problema sarebbe risolto creando una sequenza di token (caratteri negli esempi) e applicando o più delle funzioni di Clojure sequenza (doseq, dorun take-mentre, etc.)

L' l'esempio seguente legge il primo nome utente da/etc/passwd su sistemi unix like.

(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

sono uscito con questa versione:

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

Si cerca una stringa, non un singolo carattere come delimitatore!

Grazie!