【问题标题】:Improving on loop-recur改进循环递归
【发布时间】:2012-07-25 20:56:57
【问题描述】:

我编写了一个函数,试图以交互方式从用户那里得到一个是/否(是/否)的答案。它测试答案是否有效,如果不是,则再次请求用户:

(defn get-valid-answer [question]
   (println  question)
   (loop []
     (let [ans (.trim (read-line))]
        (if (#{"y" "n"} ans)
            ans
            (do (println "Please answer \"y\"[yes] or \"n\"[no] only!")
                (recur) )))))

上面带有循环递归的版本可以完成这项工作,但我觉得必须有更好(更实用)的方法来做到这一点。我宁愿只进行一次 read-line 调用。任何人都可以建议在这种情况下不使用循环递归但可能使用某些(Clojure 内置)宏的替代版本吗?

【问题讨论】:

    标签: clojure


    【解决方案1】:

    想象一个小孩没完没了地问同一个问题,直到得到满意的答复,然后用代码做同样的事情。也就是说,从层出不穷的问题中,找出第一个有效的答案。

    未经测试,但这应该可以解决问题。

    (defn ask []
      (println "Please answer \"y\"[yes] or \"n\"[no]:")
      (.trim (read-line)))
    
    (defn get-valid-answer [question]
      (println question)
      (->> (repeatedly ask)
           (filter #{"y" "n"})
           (first)))
    

    如果有两个函数困扰您,您还可以在 let 绑定中定义“询问”。

    【讨论】:

    • 这很好。我已经测试过它有效。但我对您的方法有一个疑问:我看到“反复”发出懒惰的调用来询问,我认为懒惰的函数一次评估 32 个块,因此可能有 32 个调用要问。通过我的测试,我可以看到这不会发生。 'first' 是否告诉 Clojure 覆盖 32(thunk-size)并且只进行一次调用来询问?
    • 如果您阅读了 LazySeq 的源代码 (github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/…),您可以自己看到项目是一次评估一个。我看过你提到的帖子,但我不确定那是什么时候,如果有的话。
    • 只有一些惰性序列被分块。 repeatedly 不是一个,但例如 maprange 是。
    • 还有更多内容。我找到了一个分块序列?仅当 range 和 map 返回的惰性序列被包装在序列中时才返回 true 的函数,但反复出现你总是得到 false:pastie.org/4333243
    猜你喜欢
    • 2018-09-03
    • 2018-06-27
    • 2017-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-12
    • 2011-02-09
    • 2023-04-02
    相关资源
    最近更新 更多