Idiomatic way to write Clojure code for repeatedly reading lines from the console?

徘徊边缘 提交于 2019-12-20 12:34:27

问题


Recently I was writing a little CLI script which needed to repeatedly read dates from the console (the number of dates to read was calculated and could be different each time). Sample Ruby code to give you the idea:

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

Just for the heck of it, I wrote the script in Clojure, and wound up using some rather ugly code with swap! and loop...recur. I'm wondering what the cleanest way to achieve the desired effect in Clojure would be. (Clojure does have dotimes, but it doesn't retain the values returned from evaluating the body... as might be expected from a language which emphasizes pure functional programming.)


回答1:


If your goal is to end up with a sequence of exactly x dates entered by user then:

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

or using map:

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

Beware of lazy sequences in Clojure: user will be asked to enter more dates as they are needed. If your goal is for user to enter all dates at once (say at startup) then use doall:

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

This will read all dates at once, but will parse them lazily still, so date format validation could fail much later in your program. You can move doall one level up to parse promptly as well:

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

And you can use a helper function to read line with prompt:

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

Then replace read-line with either:

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

or

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



回答2:


read-line returns nil when the end of file is reached. On the console that is when you press CTRL-d (CTRL-z on Windows).

You could use this code to take advantage of this:

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

If you must read a fixed number of lines you can use:

(repeatedly n read-line)



回答3:


You can do something like this:

(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


来源:https://stackoverflow.com/questions/11484113/idiomatic-way-to-write-clojure-code-for-repeatedly-reading-lines-from-the-consol

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!