I'm running an example in Clojure Programming by Chas Emerick et al.:
(defn make-user
[& [uid]]
{:user-id (or uid (str (java.util.UUID/randomUUID)))})
output:
=> (make-user "T-800")
{:user-id "T-800"}
Now I remove the square brackets around uid in line 2:
(defn make-user
[& uid]
{:user-id (or uid (str (java.util.UUID/randomUUID)))})
The evaluation result becomes:
=> (make-user "T-800")
{:user-id ("T-800")}
How to understand this difference?
In an argument declaration, putting arguments next to & causes them to get wraped into a list.
(defn return [x y & more]
[x y more])
(return 1 2 3 4 5 6)
;=> [1 2 (3 4 5 6)]
This wraping is useful to manipulate an undetermined number of args in a function:
(defn plus [& more] (apply + more))
(plus 3 4)
;=> 7
(plus 3 4 5 6)
;=> 18
But if we know there will only be one element as the optional argument and want to directly access it, we could use first to extract it:
(defn make-user-1 [& uid] {:user-id (first uid)})
(make-user-1 "T-800")
;=> {:user-id "T-800"}
Or, we could simply unwrap the argument element by using destructuring!
(defn make-user-2 [& [uid]] {:user-id uid})
(make-user-2 "T-800")
;=> {:user-id "T-800"}
So, here are some arg declaration and their given output:
(defn f [arg] arg) ;=> arg
(defn f [& arg] arg) ;=> (arg)
(defn f [& [arg]] arg) ;=> arg
The more you wrap args in the arg declaration, the more those unwrap in the body.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With