In Clojure you can unquote-splice a list of values to generate code, e.g.
(def extra-values [1 2 3 4])
`(+ 100 200 ~@extra-values)
=> (clojure.core/+ 100 200 1 2 3 4)
It seems logical that the same approach should work in an unquoted context, e.g.
(def extra-values [1 2 3 4])
(+ 1000 ~@extra-values)
=> [an error, but one could argue that the answer should be 1010??]
Is there any deep technical/philosphical reason why this can't work?
One simple reason is that then
`(+ 100 200 ~@extra-values)
would be poorly defined: does it expand to
(+ 100 200 1 2 3 4)
or to
(+ 100 200 ~@extra-values)
? Both are valid interpretations if the ~@
construct is legal in that context.
It also causes serious issues in the macro system. Consider
(defmacro foo [x & args]
`(list ~x ~(count args)))
(let [data '(1 2 3)]
(foo "three" ~@data))
How can foo
know what args it is being passed? It certainly can't expand that at compile-time, so now unquote-splicing is only valid in some non-quoted contexts.
And overall it's just muddying up the language to accommodate for poor understanding of core concepts - if you really want to unquote-splice to build a complicated argument list, you can easily use apply
in something like
(apply + `(100 ~@extra-values 200))
The point of syntax-quote
, unquote
, and unquote-splicing
is to help the developer to write macros.
For example, without syntax-quote
and unquote
you would have to write
user=> (list :a extra-values)
(:a [1 2 3 4])
instead of:
user=> `(:a ~extra-values)
(:a [1 2 3 4])
In the former case it is harder for the reader (human reader - not the repl) to understand what the resulting form is going to look like, whereas the latter case maintains the 'shape' of the resulting form.
So what if instead of the vector
[1 2 3 4]
we want to splice the contents of extra-values
as elements into the resulting form? We need unquote-splicing
so that we can write:
user=> `(+ 100 200 ~@extra-values)
(clojure.core/+ 100 200 1 2 3 4)
instead of:
user=> (concat `(+ 100 200) extra-values)
(clojure.core/+ 100 200 1 2 3 4)
Again the unquote-splicing
version allows the code to resemble the 'shape' of the resulting form when the code is evaluated, whereas in the latter version the 'shape' gets lost in the noise of apply
and list
.
Both these examples are very simple, but syntax-quote
and friends really come to their own when writing more complicated macros.
Coming back to your question of why you can't write (+ 1000 ~@extra-values)
? We already have that functionality in apply
(with a few more limitations):
user=> (apply + 1000 extra-values)
1010
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