2009-06-28 3 views
11

Я пытаюсь Clojure я пытаюсь выяснить, как реализовать следующий алгоритм,Clojure While Loop

Я читаю из входного потока я хочу, чтобы продолжить чтение до тех пор, пока не разделитель.

Я могу сделать это в 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

Прямо о побочном эффекте. Может быть, добавьте аккумулятор в цикл, чтобы показать, как результат построен функционально? –

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 вы обычно используете хвостовую рекурсию (которую компилятор переводит в цикл while)

Ниже приведено не совсем решение, но этот вариант цикла может быть полезен в некоторых случаях:

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

Это создаст список всех пар а и б до(< (* a b) 1000). То есть он прекратится, как только условие будет выполнено. Если вы замените: while: when, они, вы можете найти все пар, которые удовлетворяют этому условию, даже после того, как он найдет тот, который этого не делает.

5

Работа на Clojure 1.3.0, и для чего это стоит, вы можете написать в то время как петли в Clojure сейчас, сделать что-то похожее на

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

это зависит от некоторых побочных эффектов, чтобы сделать выражение истинности в конечном итоге ложным. – tenpn

3

Подход цикл будет работать нормально в Clojure однако петли/Повторять являются как правило, предпочтительны низкоуровневые операции и функции более высокого порядка.

Обычно такого рода проблема может быть решен путем создания последовательности лексем (символы в вашем примере) и применяя или более функции Clojure в последовательности (doseq, dorun, берите время и т.д.)

в следующем примере читается первое имя пользователя из/etc/passwd для unix-подобных систем.

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

Он ищет строку, а не один полукокса в качестве разделителя!

Спасибо!