2012-07-25 56 views
5

我寫了一個函數,試圖從用戶交互地獲得y/n(是/否)答案。它測試,如果答案是有效的,如果不是,再次徵求用戶:改善循環復發

(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)))))) 

上述版本與環RECUR做的工作,但我有嘮叨的感覺,必須有一個更好的(更實用)的方式來做這個。我寧願讓read-line調用只做一次。任何人都可以提出一個替代版本在這種情況下不使用loop-recur,但可能使用一些(Clojure內置)宏?

回答

7

想想一個小孩不斷問相同的問題,直到它得到滿意的答覆,然後在代碼中做同樣的事情。也就是說,從無窮無盡的問題中得到第一個有效答案。

未經測試,但這應該有所斬獲。

(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綁定,如果兩個函數你煩惱。

+0

這是整潔。我已經測試過它的工作原理。但是我有一個關於你的方法的問題:我看到'重複'會發出懶惰的請求,我認爲懶惰函數每次評估32個塊,以便可能有32個調用請求。通過我的測試,我可以看到這不會發生。 '第一'是否告訴Clojure覆蓋32(thunk-size)並且只進行一次調用? – Don 2012-07-25 22:00:09

+0

如果您閱讀LazySeq的源代碼(https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LazySeq.java),您可以看到自己的項目評估爲一個時間。我已經看到了你指的帖子,但我不確定這是否屬實。 – Ben 2012-07-25 22:18:44

+0

感謝您的跟進。 – Don 2012-07-25 22:29:23