Clojure Пока Петля - PullRequest
       9

Clojure Пока Петля

11 голосов
/ 28 июня 2009

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

Я читаю из входного потока и хочу продолжить чтение, пока он не станет символом-разделителем.

Я могу сделать это в Java с помощью цикла while, но я не могу понять, как это сделать в clojure?

while
   read
   readChar != delimiter

   do some processing....
end while

Ответы [ 6 ]

10 голосов
/ 28 июня 2009

Я не знаю Clojure, но похоже, что, как и Scheme, он поддерживает циклы let:

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

Надеюсь, этого достаточно, чтобы вы начали. Я ответил http://clojure.org/special_forms#toc9, чтобы ответить на этот вопрос.

ПРИМЕЧАНИЕ: я знаю, что Clojure не поощряет побочные эффекты, поэтому, вероятно, вы хотите вернуть что-то полезное вместо '().

5 голосов
/ 26 декабря 2011

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

(while truth-expression
  (call-some-function))
3 голосов
/ 27 декабря 2011

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

Обычно проблему такого рода можно решить, создав последовательность токенов (символы в вашем примере) и применив к или более из функций последовательности clojure (доза q, dorun, take-while и т. Д.)

Следующий пример читает первое имя пользователя из / 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)))
2 голосов
/ 29 июня 2009

Я придумал это в духе 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))))))))))

Полная паста .

1 голос
/ 18 февраля 2011

Цикл while обычно включает в себя изменяемые переменные, то есть ожидание, пока переменная не удовлетворяет определенному условию; в Clojure вы обычно используете хвостовую рекурсию (которую компилятор преобразует в цикл while)

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

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

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

0 голосов
/ 03 июня 2015

Я вышел с этой версией:

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

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

Спасибо!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...