Destruction of a constrained variational function: impossible?

Until now, I have always believed that whatever you can do in the binding let

, you can do in the argument vector for the form defn


However, I just noticed this - if I do it with a bind let

, it works:

(let [[x & more :as full-list] (range 10)]
  (println "x:" x) 
  (println "more:" more) 
  (println "full list:" full-list))

; x: 0 
; more: (1 2 3 4 5 6 7 8 9) 
; full list: (0 1 2 3 4 5 6 7 8 9)


But if I try to output it to a function, I get an exception:

(defn foo [x & more :as full-list]
  (println "x:" x) 
  (println "more:" more) 
  (println "full list:" full-list))

; CompilerException java.lang.RuntimeException: Unexpected parameter, compiling:(/tmp/form-init615613631940782255.clj:1:1)


It should be noted that this works:

(defn foo [[x & more :as full-list]]
  (println "x:" x) 
  (println "more:" more) 
  (println "full list:" full-list))


But then I have to pass the argument as a collection i.e. (foo [1 2 3])


Is it possible to define a function that takes a variable number of arguments and bind the entire group of arguments to a local variable without using the binding let

internally? It seems strange to me that you can't just do (defn foo [x & more :as full-list] ...

it. Is there any special reason why this doesn't work (or shouldn't)?


source to share

1 answer

If you want a variable number of arguments, you don't see &:

(defn foo [& [x & more :as full-list]]
  (println "x:" x) 
  (println "more:" more) 
  (println "full list:" full-list))


Clojure's parameter definition has only one special case, which is &

char to indicate the variational number of arguments. The rest are simple simple arguments.

Now every simple argument can be destroyed using map or list syntax. For example:

(defn foo [ x y ] ...)


Can be destroyed as:

(defn foo [[x1 x2 & x-more :as x] {:keys [y1 y2 y3]}] ...)


So we say that we expect the first parameter to be a list of at least 2 items, and the second parameter is a map with some keys. Note that this will still be a two-parameter fn and that Clojure will not enforce that x actually has at least two elements. If x is an empty list, x1 and x2 will be nil.

Going back to your question, if you look at my answer, you can see that my fn has 0 required parameters with variable number of arguments, and the one you have has 1 required parameter with variable number of arguments. What I am doing is just destroying var arg.



All Articles