Note: Not a duplicate of Why does Clojure recur think it should only have one argument?. I’m not using a loop.
(def t
#(let [[low high] (sort %&)] {:low low :high h}))
(t 3 2)
=> {:low 2, :high 3}
Given that this works as expected. How come this doesn’t:
(def t
#(let [[low high] (sort %&)]
(if (= 0 low)
nil
(do
(println {:low low :high high})
(recur low (dec high))))))
(t 3 2)
=> java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2
Given that it says that it is expecting 1 argument I can guess that I can make it work by turning the arguments into a collection:
(def t
#(let [[low high] (sort %&)]
(if (= 0 low)
nil
(do
(println {:low low :high high})
(recur [low (dec high)])))))
(t 3 2)
=> {:low 2, :high 3}
{:low 2, :high 2}
{:low 1, :high 2}
{:low 1, :high 1}
nil
… but why?
This is just how it was designed. The Clojure website says:
I presume it was designed this way because if the function itself is giving you a sequence (and not individual arguments) then it would be more natural for the recur form to instead accept a sequence, or something that can become a sequence. If this was not the case, you would then need to break apart the given sequence in order to perform the recursion.
Your example doesn’t seem to fit the mold because it looks like you really only care about having two arguments, which means you really don’t need the rest args. You would probably be better off explicitly defining the two arguments and determining which is low and high in the let statement, instead of sorting the rest args and destructuring them.
Here’s your code with minimal modification. I wrapped the two explicit arguments in a vector before passing them into sort (essentially mimicing rest args), and passed two arguments into recur.
However, while keeping the recur form, I would probably refactor this a little bit: