can someone tell me what the word “special” means in this documentation of macros in clojure docs? In the Common Lisp specification a “special variable” is a variable which has been bound dynamically. Is that the meaning here? https://clojure.org/reference/macros
I have some comments to say about &form and &env. Is there a place in the clojure docs wiki Is the best place here? https://clojuredocs.org/clojure.core/defmacro
Sounds like a good place to me
I don’t know the clojure optional argument syntax very well. Is there a way to pass an optional argument to a macro? For example my macro is defined something like this:
(defmacro rte-case [sequence & clauses] ...)
However, with it is called inside the expansion of another macro, I’d like to pass an additional argument somehow. Do I need to hack this? like use :special-argument as the value of sequence and then pare the argument list myself. yuck. or is there a better way.
`(rte-case :special-argument {:blah 1 :foo 2} ~sequence ~@clauses)
I’m looking for something like
(defmacro rte-case [sequence &key special-argument & clauses] ...)
and if the macro is called as (rte-case ~my-seq :special-argument foo ~@clauses) then special-argument is bound to the given value.There’s something similar in the sh function which special cases the keywords at the end of the argument list.
(println (sh "ls" "-l"))
(println (sh "ls" "-l" "/no-such-thing"))
(println (sh "sed" "s/[aeiou]/oo/g" :in "hello there\n"))
(println (sh "sed" "s/[aeiou]/oo/g" :in (java.io.StringReader. "hello there\n")))
(println (sh "cat" :in "x\u25bax\n"))
(println (sh "echo" "x\u25bax"))
(println (sh "echo" "x\u25bax" :out-enc "ISO-8859-1")) ; reads 4 single-byte chars
(println (sh "cat" "myimage.png" :out-enc :bytes)) ; reads binary file into bytes[]
(println (sh "cmd" "/c dir 1>&2"))
These are typically called kwargs if that helps searching. Use & clauses in the param list. clauses will be a sequence but you can destructure it as if it is a map
will I be able to use the call-site syntax: (foo :key1 100 :key2 200 clause1 clause2 clause3)
Or does the call-site have to consist totally of keyword/value pairs after the first keyword is given?
It should consist of key value pairs
I’m trying to figure out how to do the following. I have one macro which in its expansion includes another macro call. in the inner macro I need to emit an error message. I could make a much better error message if I had access to the &body of the parent macro expansion. In this example there is an &body of destructuring case which has line-number information about the call-site. However, -destructuring-fn-many is also a macro, and it would like to emit an error message. I could make a much more human readable error message if I had call-site information from destructuring-case
(defmacro destructuring-case
[expr & operands]
(cond
(not= 0 (mod (count operands) 2))
(throw (ex-info (cl-format false
"destructuring-case expects multiple of 2 number of operands after the first:~
not ~A, ~A"
(count operands) (apply list 'destructuring-case expr operands))
{:error-type :invalid-destructuring-case-call-site
:expr expr
:operands operands}))
:else
(let [pairs (partition 2 operands) ]
`(apply (-destructuring-fn-many nil ~@pairs) ~expr))))The vars &form and &env are "special" because you don't do anything to bind them in the macro definition. Macros are invoked with those 2 "extra" parameters which are provided by the compiler at macroexpansion time
a macro does not have access to the surrounding form of it's usage
ok, so I could dynamically bind my own copy of &form (and its metadata) to use in the sub macro expansion which is “private” anyway. is that the correct approach, or am I doing something I will regret later?
or I could even pass it as an explicit parameter to -destructuring-fn-many` since it is private.
they are not dynamic vars, so you can't bind them
you would need to explicitly pass that info down
but don't call it &form or &env! those names really are special