Don
Don

Reputation: 1221

Improving on loop-recur

I wrote a function that tries to get a y/n (yes/no) answer from a user interactively. It tests if the answer is valid and if not, solicits the user again:

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

The above version with loop-recur does the job but I have nagging feeling that there must be a better (more functional) way to do this. I would prefer to have the read-line call made just once. Could anyone suggest an alternative version not using loop-recur in this scenario but possibly using some (Clojure builtin) macro instead?

Upvotes: 5

Views: 285

Answers (1)

Ben
Ben

Reputation: 6059

Think of a small child asking the same question endlessly until it gets a satisfactory reply, then do the same thing in code. That is to say, take the first valid answer from an endless stream of questions.

Untested, but this should do the trick.

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

You could also define 'ask' in a let binding, if two functions bothers you.

Upvotes: 7

Related Questions