2009-06-28 13 views
11

I tratando clojure Estoy tratando de encontrar la manera de poner en práctica el siguiente algoritmo,Clojure ciclo Mientras

estoy leyendo desde un flujo de entrada quiero seguir leyendo hasta que no es un carácter delimitador.

puedo hacer esto en java con un ciclo while pero no puedo encontrar la manera de hacerlo en clojure?

 
while 
    read 
    readChar != delimiter 

    do some processing.... 
end while 

Respuesta

10

no sé Clojure, pero parece que, al igual Esquema, es compatible con "dejar que los ciclos":

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

Hope esto es suficiente para empezar. Me he referido al http://clojure.org/special_forms#toc9 para responder a esta pregunta.

NOTA: Sé que Clojure desalienta los efectos secundarios, por lo que presumiblemente desea devolver algo útil en lugar de '().

+0

Derecho sobre el efecto secundario. ¿Tal vez agregar un acumulador al ciclo para mostrar cómo se construye un resultado funcionalmente? –

2

Se me ocurrió esto en el espíritu de line-seq. Es completamente vago y exhibe más de la naturaleza funcional de Clojure que 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

Tengo que ser una forma más corta de hacerlo. – Kzqai

1

Un ciclo while generalmente involucra variables variables, es decir, esperar hasta que una variable cumpla una cierta condición; en Clojure normalmente usaría recursividad de cola (que el compilador traduce en un ciclo while)

La siguiente no es una solución, pero esta variación del for-loop podría ser de ayuda en algunos casos:

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

Esto creará una lista de todos los pares de a y b hasta(< (* a b) 1000). Es decir, se detendrá tan pronto como se cumpla la condición. Si reemplaza: while with: when, puede encontrar all de los pares que cumplen la condición, incluso después de encontrar uno que no lo hace.

5

Trabajando en Clojure 1.3.0, y por lo que vale la pena, puede escribir mientras bucles en Clojure ahora haciendo algo parecido a

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

esto depende de algunos efectos secundarios para hacer que la expresión de la verdad eventualmente falle. – tenpn

3

El enfoque de bucle no tendrán ningún problema en clojure embargo bucle/repiten son se consideran operaciones de bajo nivel y funciones de orden superior generalmente preferidas.

Normalmente este tipo de problema se resolvería mediante la creación de una secuencia de símbolos (caracteres en el ejemplo) y la aplicación de o más de las funciones de clojure secuencia (doseq, doRun, llevar tiempo, etc.)

El El siguiente ejemplo lee el primer nombre de usuario de/etc/passwd en sistemas como 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

he salido con esta versión:

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

Busca una cadena, no un solo carbón como delimitador!

Gracias!