Question

As an answer to a question on SO I was building a recurring function, and built my most complicated destructuring yet, which miraculously worked:

(defn fib?
  [a b & [c & r]]
  (if (= c (+ a b))
    (if r
      (recur b c r)
      true)
    false))

(fib? 0 1 1)
=> true

(fib? 2 3 5 8 13)
=> true

But I have no idea why it should work. The r used in therecur is a collection, something which would make the original function fail.

(fib? 2 3 [5 8 13])
=> false

I wanted to use something like apply recur there, but since recur is a special form, that's not possible. So I tried without it and it worked. Does recur have magical auto-apply properties or is there something else I'm not seeing.

Était-ce utile?

La solution

The are two parts to the answer:

  1. The "rest" parameter of a variadic function becomes the final parameter in any recur forms that recur to the top of the function. At this point it is no longer special in any way. You'll normally want to ensure that any values passed in that position actually are sequential, but even this is not enforced.1

  2. Destructuring is just syntactic sugar provided by the fn and let macros. The desugared version of an fn form that uses destructuring in its parameter vector takes a certain number of regular arguments, then destructures them in a let form wrapping the entire body. Thus if you recur to the top of a function that uses destructuring in its parameter vector, the new values will be destructured for the next iteration.


1 For example, ((fn [& xs] (if (seq? xs) (recur (first xs)) xs)) 1 2 3) returns 1.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top