ChrisR
ChrisR

Reputation: 1237

A Clojure binding question

just looking to re factor some simple code

I have a function

(defn foo
    ([x y]
        (let [line [x y]]
            (...))
    ([x y z]
        (let [plane [x y z]]
            (...))))

I know I can write

(let [[x y :as point] [1 0]])

Is there a similar destructuring for functions such as foo where I can write [x y :as line] or [x y z :as plane] in the actual defn? (i.e plane would be assigned [x y z])

Upvotes: 1

Views: 116

Answers (2)

mikera
mikera

Reputation: 106351

You can always build the lets using a macro. This would enable you to two write something like:

(def foo
  (build-foo-args [[x y] line]
     (...))
  (build-foo-args [[x y z] plane]
     (...)))

Not sure how much this syntactic sugar really buys you though... the lets are pretty clear in the first place.

On the whole, I'd probably recommend rethinking your function signature:

  • If you genuinely need different behaviours for different arities then foo should probably be split into separate functions.

  • If the behaviour is the same for different arities, then I would use variadic args as suggested by Dave Ray, but call the combined argument something neutral e.g. "normal-vector" which can refer to multiple dimensionalities. You may find you don't actually need x,y,z to be named at all....

Upvotes: 2

Dave Ray
Dave Ray

Reputation: 40005

You can destructure in the arg list as well, but you'll have to use variadic args which means you can't have multiple signatures:

(defn foo [& [x y z :as plane]]
  (...))

and then call like:

(foo 1 2 3)

but like I said above, with this approach the two and three arg forms become ambiguous so you'd have to have separate named functions.

Upvotes: 2

Related Questions