Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure: Why does if-let only allow 2 forms in the binding vector?

Tags:

clojure

When I use if-let like

(if-let [a 2 b nil] (+ a b))

I get an IllegalArgumentException:

clojure.core/if-let requires exactly 2 forms in binding vector...

Similar for when-let...

This is not what I would expect. If-let could try all bindings and break when one fails and evaluate the else expression.

The same complaint can be found in the comments at clojuredocs. I found an answer here which did not really satisfy since the poster seems to have the equivalent of a nested if-let-structure in mind.

What reasons are there to limit the bindings of the *-let macros?

UPDATE: As it seems to be unclear, what my expectations of if-let are:

  • It should evaluate all bindings sequentially.
  • When all succeed, it should evaluate the 'then'-case.
  • If one binding fails it should immediately break and evaluate the 'else'-case.
  • In case of failure the bindings, even succeeded ones, should not be available in the 'else'-expression
like image 759
nansen Avatar asked Apr 25 '13 20:04

nansen


1 Answers

Try this out:

(defmacro if-let-multi
  ([bindings then-exp]
     (let [values (take-nth 2 (rest bindings))]
       `(if (and ~@values) (let ~bindings ~then-exp) false)))
  ([bindings then-exp else-exp]
     (let [values (take-nth 2 (rest bindings))]
       `(if (and ~@values) (let ~bindings ~then-exp) ~else-exp))))

Here it is in action:

user> (if-let-multi [a 2 b nil] (+ a b))
false
user> (if-let-multi [a 2 b 3] (+ a b))
5
user> (if-let-multi [a 2 b nil] (+ a b) "NO WAY")
"NO WAY"
like image 95
WolfeFan Avatar answered Oct 20 '22 03:10

WolfeFan