Search code examples
clojure

Why don't when-let and if-let support multiple bindings by default?


Why don't when-let and if-let support multiple bindings by default?

So:

(when-let [a ...
           b ...]
  (+ a b))

...instead of:

(when-let [a ...
  (when-let [b ...
    (+ a b)))

I am aware that I can write my own macro or use a monad (as described here: http://inclojurewetrust.blogspot.com/2010/12/when-let-maybe.html).


Solution

  • Because (for if-let, at least) it's not obvious what to do with the "else" cases.

    At least, motivated by Better way to nest if-let in clojure I started to write a macro that did this. Given

    (if-let* [a ...
              b ...]
      action
      other)
    

    it would generate

    (if-let [a ...]
      (if-let [b ...]
        action
        ?))
    

    and it wasn't clear to me how to continue (there are two places for "else").

    You can say that there should be a single alternative for any failure, or none for when-let, but if any of the tests mutate state then things are still going to get messy.

    In short, it's a little more complicated than I expected, and so I guess the current approach avoids having to make a call on what the solution should be.

    Another way of saying the same thing: you're assuming if-let should nest like let. A better model might be cond, which isn't a "nested if" but more an "alternative if", and so doesn't fit well with scopes... or, yet another way of saying it: if doesn't handle this case any better.