编写Clojure代码以便从控制台重复读取行的惯用方法?

时间:2012-07-14 13:23:31

标签: command-line clojure functional-programming console-input

最近我写了一个小的CLI脚本,需要重复从控制台读取日期(计算读取的日期数量,每次都可能不同)。示例Ruby代码为您提供了想法:

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

只是为了它,我在Clojure中编写了脚本,并使用swap!loop...recur使用了一些相当丑陋的代码。我想知道在Clojure中达到预期效果最干净的方法是什么。 (Clojure确实有dotimes,但它没有保留从评估正文返回的值......正如强调纯函数式编程的语言所期望的那样。)

3 个答案:

答案 0 :(得分:10)

当达到文件末尾时,

读取行返回nil。在按CTRL-d (Windows上的CTRL-z)时的控制台上。

您可以使用此代码来利用此功能:

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

如果您必须阅读固定数量的行,您可以使用:

(repeatedly n read-line)

答案 1 :(得分:8)

如果您的目标是以用户输入的一系列x日期结束,那么:

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

或使用map

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

谨防Clojure中的延迟序列:系统会要求用户根据需要输入更多日期。如果您的目标是让用户一次输入所有日期(例如在启动时),请使用doall

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

这将一次读取所有日期,但仍会懒散地解析它们,因此日期格式验证可能会在程序中稍后失败。您可以将doall一级移动到即时解析:

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

你可以使用辅助函数来读取带有提示符的行:

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

然后将read-line替换为:

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

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

答案 2 :(得分:4)

您可以这样做:

(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