9

Recientemente estaba escribiendo un pequeño script CLI que necesitaba leer repetidamente las fechas de la consola (se calculó el número de fechas para leer y podría ser diferente cada vez). Muestra el código Ruby para darle la idea:¿Forma idiomática de escribir el código de Clojure para leer líneas repetidamente desde la consola?

dates = x.times.collect { print "Enter date: "; Date.parse(gets.chomp) } 

Sólo por el gusto de hacerlo, me escribió el guión en Clojure, y terminó utilizando un código bastante feo con swap! y loop...recur. Me pregunto cuál sería la forma más limpia de lograr el efecto deseado en Clojure. (Clojure tiene dotimes, pero no retiene los valores devueltos por la evaluación del cuerpo ... como podría esperarse de un lenguaje que hace hincapié en la programación funcional pura.)

Respuesta

7

Si su objetivo es acabar con una secuencia de exactamente x fechas introducida por el usuario a continuación:

(for [line (repeatedly x read-line)] (DateFormat/parse line)) 

o usando map:

(map DateFormat/parse (repeatedly x read-line)) 

Cuidado con secuencias de descanso bajo Clojure: Se exigirá usuario que introduzca más fechas a medida que se necesitan. Si su objetivo es para que el usuario ingrese todas las fechas a la vez (digamos en el arranque) a continuación, utilizar doall:

(map DateFormat/parse (doall (repeatedly x read-line))) 

Esto le leer todas las fechas a la vez, sino que analizarlos con pereza todavía, por lo que la validación de formato de fecha podría fallas mucho más tarde en tu programa. Puede mover doall un nivel por encima de analizar con prontitud, así:

(doall (map DateFormat/parse (repeatedly x read-line))) 

Y puede utilizar una función de ayuda para leer línea con indicador:

(defn read-line-with-prompt [prompt] 
    (print prompt) 
    (read-line)) 

luego vuelva a colocar read-line con:

#(read-line-with-prompt "Enter date: ") 

o

(partial read-line-with-prompt "Enter date: ") 
+0

Excelente respuesta ... gracias por brindar tantas opciones. Creo que definiré una función de ayuda 'leer fecha 'y simplemente usar' (varias veces x fecha de lectura) '. Creo que el procesamiento posterior obligará a la evaluación antes de hacer cualquier otra cosa con la consola, por lo que 'doall' * probablemente * será innecesario, pero es genial tener eso en mi kit de herramientas y estoy seguro de que voy a encontrar posibilidades de usar eso mas tarde. –

4

se puede hacer algo como esto:

(defn read-dates [n] 
    (doall (for [_ (range n)] (java.util.Date/parse (read-line))))) 

(def my-dates (read-dates 5)) ;Read 5 dates from console 
10

read-line devuelve nil cuando se llega al final del archivo. En la consola que es cuando presiona CTRL-d (CTRL-z en Windows).

Se podría utilizar este código para tomar ventaja de esto:

(doseq [line (repeatedly read-line) :while line] 
    (do-something-with line)) 

Si tiene que leer un número fijo de líneas se puede utilizar:

(repeatedly n read-line) 
+1

Uso muy interesante de ': while' en' doseq', nunca lo había visto antes. ¡Guay! – dimagog

Cuestiones relacionadas