Pregunta

Estoy intentando clojure, estoy tratando de descubrir cómo implementar el siguiente algoritmo,

Estoy leyendo desde una secuencia de entrada que quiero seguir leyendo hasta que no sea un carácter delimitador.

¿Puedo hacer esto en Java con un ciclo while pero parece que no puedo entender cómo hacerlo en clojure?

while
   read
   readChar != delimiter

   do some processing....
end while
¿Fue útil?

Solución

No sé Clojure, pero parece que, al igual que Scheme, admite " let loops " ;:

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

Espero que esto sea suficiente para comenzar. Me referí a http://clojure.org/special_forms#toc9 para responder esta pregunta.

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

Otros consejos

Trabajando en Clojure 1.3.0, y por lo que vale, puede escribir bucles while en Clojure ahora haciendo algo similar a

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

El enfoque de bucle funcionará bien en clojure, sin embargo, el bucle / repetición se consideran operaciones de bajo nivel y generalmente se prefieren las funciones de orden superior.

Normalmente, este tipo de problema se resolvería creando una secuencia de tokens (caracteres en su ejemplo) y aplicando o más funciones de secuencia de clojure (doseq, dorun, take-while, etc.)

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

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

Pasta completa .

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

Lo siguiente no es una solución, pero esta variación del ciclo for podría ser útil 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 ayb hasta (< (* a b) 1000). Es decir, se detendrá tan pronto como se cumpla la condición. Si reemplaza: while con: when, pueden encontrar todos los pares que cumplen con la condición, incluso después de que encuentre uno que no lo haga.

Salí 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 un String, no un solo carácter como delimitador!

¡Gracias!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top