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

Ale*_*x D 10 command-line functional-programming clojure console-input

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

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

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

Ale*_*min 10

当到达文件末尾时,read-line返回nil.在按CTRL-d (Windows上的CTRL-z)时的控制台.

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

(doseq [line (repeatedly read-line) :while line]
    (do-something-with line))
Run Code Online (Sandbox Code Playgroud)

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

(repeatedly n read-line)
Run Code Online (Sandbox Code Playgroud)


Dim*_*gog 8

如果您的目标是最终x得到用户输入的一系列完全日期,那么:

(for [line (repeatedly x read-line)] (DateFormat/parse line))
Run Code Online (Sandbox Code Playgroud)

或使用map:

(map DateFormat/parse (repeatedly x read-line))
Run Code Online (Sandbox Code Playgroud)

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

(map DateFormat/parse (doall (repeatedly x read-line)))
Run Code Online (Sandbox Code Playgroud)

这将立即读取所有日期,但仍将懒惰地解析它们,因此日期格式验证可能会在程序中稍后失败.您可以将doall一个级别向上移动以便及时解析:

(doall (map DateFormat/parse (repeatedly x read-line)))
Run Code Online (Sandbox Code Playgroud)

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

(defn read-line-with-prompt [prompt]
  (print prompt)
  (read-line))
Run Code Online (Sandbox Code Playgroud)

然后替换read-line为:

#(read-line-with-prompt "Enter date: ")
Run Code Online (Sandbox Code Playgroud)

要么

(partial read-line-with-prompt "Enter date: ")
Run Code Online (Sandbox Code Playgroud)