Confusing clojure macro var evaluation - macros

I am trying to write a clojure macro that transforms clojure keywords to java enums. But the evaluation of the parameters in a macro is confusing:
user=> (defmacro show-and-tell [thing]
#_=> `(vector ~(name thing) ~(type thing) ~thing))
#'user/show-and-tell
user=> (macroexpand-1 (show-and-tell :foo))
["foo" clojure.lang.Keyword :foo]
user=> (def foo :bar)
#'user/foo
user=> (name foo)
"bar"
user=> (type foo)
clojure.lang.Keyword
user=> (macroexpand-1 (show-and-tell foo))
["foo" clojure.lang.Symbol :bar]
So it works as I would expect if the keyword is provided directly as a parameter. But if it is a var, I don't get the correct name and type of the thingy.
I can make it 'sort-of-almost' work by using eval:
user=> (defmacro show-and-tell-with-eval [thing]
#_=> `(vector ~(name (eval thing)) ~(type (eval thing)) ~(eval thing)))
#'user/show-and-tell-with-eval
user=> (macroexpand-1 '(show-and-tell-with-eval foo))
(clojure.core/vector "bar" clojure.lang.Keyword :bar)
user=> (let [baz :bar-foo] (macroexpand-1 '(show-and-tell baz)))
(clojure.core/vector "baz" clojure.lang.Symbol baz)
user=> (let [baz :bar-foo] (macroexpand-1 '(show-and-tell-with-eval baz)))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: baz in this context
Can someone explain this to me? Is there no way to see the name of a (local) var inside a macro?

You might wanted to write
(defmacro show-and-tell [thing] `(vector (name ~thing) (type ~thing) ~thing))
Ad-hoc explanation:
The key to understand what's going on is to know when the arguments are evaluated. Macros take unevaluated data structures as arguments and return a data structure which is then evaluated using the rules above. Using the ~ you tell the compiler which data structures should be evaluated at runtime, thus, your thing argument, not the return value of (name thing) value as the thing value will be bound at compile time in the latter case which is not what you wanted
Here you have a further explanation about writing macros http://www.braveclojure.com/writing-macros/

You seem to be confused about the relation between vars and what they contain and how macros come into play. "Vars provide a mechanism to refer to a mutable storage location" (cf. the offical docs on Vars). When you evaluate foo in the REPL, Clojure will evaluate it according to the rules outlined in the offical docs for evaluation which in this case means, it resolves the symbol to "the value of the binding of the global var named by the symbol".
Now, it's crucial to understand that macros "are functions that manipulate forms, allowing for syntactic abstraction". Basically macros allow direct access to any parameter handed to the macro and then manipulate and evaluate the related data as needed. Let's take a glance at your macro and what happens in your "erroneous" case:
(defmacro show-and-tell [thing]
`(vector ~(name thing) ~(type thing) ~thing))
Your macro definition gets fed some thing (whatever is the parameter to show-and-tell). At this point, thing will not be resolved. Only in your macro definition you have some evaluations. Please note that in this call, you're calling macroexpand-1 on the (evaluated) result of (show-and-tell foo) which is probably not what you want:
user=> (macroexpand-1 (show-and-tell foo))
["foo" clojure.lang.Symbol :bar]
Quoting the call shows what's going on:
user=> (macroexpand-1 '(show-and-tell foo))
(clojure.core/vector "foo" clojure.lang.Symbol foo)
You're calling vector with "foo" (i.e. the name of foo) where foo is a symbol and then your code will resolve foo normally (and give :bar).
From your description, you seem to expect that normal symbol resolution will take place for all your arguments. If this is what you want, you don't need a macro in the first place. But just for the record, by now it should be obvious what you need to do: you need to evalute thing first (which is pretty much what you did with eval). In other words, you placed your unquote operator wrong:
(defmacro show-and-tell [thing]
`(vector (name ~thing) (type ~thing) ~thing))
user=> (macroexpand-1 '(show-and-tell foo))
(clojure.core/vector (clojure.core/name foo) (clojure.core/type foo) foo)
user=> (show-and-tell foo)
["bar" clojure.lang.Keyword :bar]

Related

Clojure: creating a macro to quote every symbols of a map

I am trying to write a macro that takes a map as input, and that will quote every symbol that exists in that map (keys & values).
Here is what I would like to do. Let's say I have a macro quote-everything that take a map like this as input:
{foo "foo" :bar bar}
Then, evaluating:
(quote-everything {foo "foo" :bar bar})
Would produce:
{quote(foo) "foo" :bar quote(bar)}
Basically, I want the macro to generate a new map where every symbols are quoted. The problem is that I am don't know where to start, and if it is even possible. The thing is that the map can be anything, and the macro should support nested maps as well.
The detection of the symbols could be done using symbol?. However, to support nested maps the macro should probably call itself. But I have no idea how the new map should be created with such a macro.
Any pointers would be appreciated.
The quote special form already does this for you:
user> (= (quote {foo "foo" :bar bar})
{(quote foo) "foo" :bar (quote bar)})
;; => true
All quotation does is prevents a form from being evaluated. I think you might be making this harder than it needs to be.
clojure.walk/postwalk might help you here:
(require '[clojure.walk :as w])
(w/postwalk
(fn [x]
(if (symbol? x)
`(quote ~x)
x))
'{foo :foo :bar bar})
;; => {(quote foo) :foo, :bar (quote bar)}
Wrap that in a defmacro and it should get you started. Note that that really quotes every symbol, so if you have something like (inc 1) in there it will end up as ((quote inc) 1). That might actually be what you want, I just thought I'd mention it.

Dynamic scope in macros

Is there a clean way of implementing dynamic scope that will "reach" into macro calls? Perhaps more importantly, even if there is, should it be avoided?
Here's what I'm seeing in a REPL:
user> (def ^:dynamic *a* nil)
> #'user/*a*
user> (defn f-get-a [] *a*)
> #'user/f-get-a
user> (defmacro m-get-a [] *a*)
> #'user/m-get-a
user> (binding [*a* "boop"] (f-get-a))
> "boop"
user> (binding [*a* "boop"] (m-get-a))
> nil
This m-get-a macro isn't my actual goal, it's just a boiled down version of the problem I have been running into. It took me a while to realize, though, because I kept debugging with macroexpand, which makes everything seem fine:
user> (binding [*a* "boop"] (macroexpand '(m-get-a)))
> "boop"
Doing macroexpand-all (used from clojure.walk) on the outer binding call leads me to believe that the "issue" (or feature, as the case may be) is that (m-get-a) is getting evaluated before the dynamic binding takes:
user> (macroexpand-all '(binding [*a* "boop"] (f-get-a)))
> (let* []
(clojure.core/push-thread-bindings (clojure.core/hash-map #'*a* "boop"))
(try (f-get-a) (finally (clojure.core/pop-thread-bindings))))
user> (macroexpand-all '(binding [*a* "boop"] (m-get-a)))
> (let* []
(clojure.core/push-thread-bindings (clojure.core/hash-map #'*a* "boop"))
(try nil (finally (clojure.core/pop-thread-bindings))))
Here's my crack at a workaround:
(defmacro macro-binding
[binding-vec expr]
(let [binding-map (reduce (fn [m [symb value]]
(assoc m (resolve symb) value))
{}
(partition 2 binding-vec))]
(push-thread-bindings binding-map)
(try (macroexpand expr)
(finally (pop-thread-bindings)))))
It will evaluate a single macro expression with the relevant dynamic bindings. But I don't like using macroexpand in a macro, that just seems wrong. It also seems wrong to resolve symbols in a macro--it feels like a half-assed eval.
Ultimately, I'm writing a relatively lightweight interpreter for a "language" called qgame, and I'd like the ability to define some dynamic rendering function outside of the context of the interpreter execution stuff. The rendering function can perform some visualization of sequential instruction calls and intermediate states. I was using macros to handle the interpreter execution stuff. As of now, I've actually switched to using no macros at all, and also I have the renderer function as an argument to my execution function. It honestly seems way simpler that way, anyways.
But I'm still curious. Is this an intended feature of Clojure, that macros don't have access to dynamic bindings? Is it possible to work around it anyways (without resorting to dark magic)? What are the risks of doing so?
Macro expansion take place during the compilation of you program, so it's imposisble to predict the future value of dynamic variable at that time.
But, probably, you don't need to evaluate *a* during macro expansion and just wants to leave it as is. It this case *a* will be evaluated when the actual code is called. In this case you should quote it with ` symbol:
(defmacro m-get-a [] `*a*)
Your implementation of m-get-a causes clojure to replace (m-get-a) with its value when the code is compiled, which is the core binding of *a*, while my wersion causes it to replace (m-get-a) with variable *a* itself.
You need to quote *a* to make it work:
user=> (def ^:dynamic *a* nil)
#'user/*a*
user=> (defmacro m-get-a [] `*a*)
#'user/m-get-a
user=> (binding [*a* "boop"] (m-get-a))
"boop"

Clojure var-defining macro

I just learning macros and clojure macros in particular and i'm curious is it possible to do something like this:
(defmacro with-a=hello [f]
`(let [a "hello"] ~f))
(with-a=hello (println a))
This not works for me and throws error: CompilerException java.lang.RuntimeException: Can't let qualified name: user/a, compiling:(NO_SOURCE_PATH:1)
As i undelstand for now, scheme's define-syntax allow to do something like this, but is there clojure way for this ?
By default the syntax-quote form ` prevents introducing un-namespaced symbols and symbol capture in macros. When you intentionally do this you can use the sequence ~' to introduce an unqualified symbol into a macro.
(defmacro with-a=hello [f]
`(let [~'a "hello"] ~f))
user> (with-a=hello (println a))
hello
nil
macros that do this have the fancy name anaphoric macros

lisp macro expand with partial eval

I have following code which confuse me now, I hope some can tell me the difference and how to fix this.
(defmacro tm(a)
`(concat ,(symbol-name a)))
(defun tf(a)
(list (quote concat) (symbol-name a)))
I just think they should be the same effect, but actually they seem not.
I try to following call:
CL-USER> (tf 'foo)
(CONCAT "FOO")
CL-USER> (tm 'foo)
value 'FOO is not of the expected type SYMBOL.
[Condition of type TYPE-ERROR]
So, what's the problem?
What i want is:
(tm 'foo) ==> (CONCAT "FOO")
The first problem is that 'foo is expanded by the reader to (quote foo), which is not a symbol, but a list. The macro tries to expand (tm (quote foo)). The list (quote foo) is passed as the parameter a to the macro expansion function, which tries to get its symbol-name. A list is not a valid argument for symbol-name. Therefore, your macro expansion fails.
The second problem is that while (tm foo) (note: no quote) does expand to (concat "FOO"), this form will then be executed by the REPL, so that this is also not the same as your tf function. This is not surprising, of course, because macros do different things than functions.
First, note that
`(concat ,(symbol-name a))
and
(list (quote concat) (symbol-name a))
do the exact same thing. They are equivalent pieces of code (backquote syntax isn't restricted to macro bodies!): Both construct a list whose first element is the symbol CONCAT and whose second element is the symbol name of whatever the variable A refers to.
Clearly, this only makes sense if A refers to a symbol, which, as Svante has pointed out, isn't the case in the macro call example.
You could, of course, extract the symbol from the list (QUOTE FOO), but that prevents you from calling the macro like this:
(let ((x 'foo))
(tm x))
which raises the question of why you would event want to force the user of the macro to explicitly quote the symbol where it needs to be a literal constant anyway.
Second, the way macros work is this: They take pieces of code (such as (QUOTE FOO)) as arguments and produce a new piece of code that, upon macroexpansion, (more or less) replaces the macro call in the source code. It is often useful to reuse macro arguments within the generated code by putting them where they are going to be evaluated later, such as in
(defmacro tm2 (a)
`(print (symbol-name ,a)))
Think about what this piece of code does and whether or not my let example above works now. That should get you on the right track.
Finally, a piece of advice: Avoid macros when a function will do. It will make life much easier for both the implementer and the user.

Use a clojure macro to automatically create getters and setters inside a reify call

I am trying to implement a huge Java interface with numerous (~50) getter and setter methods (some with irregular names). I thought it would be nice to use a macro to reduce the amount of code. So instead of
(def data (atom {:x nil}))
(reify HugeInterface
(getX [this] (:x #data))
(setX [this v] (swap! data assoc :x v)))
I want to be able to write
(def data (atom {:x nil}))
(reify HugeInterface
(set-and-get getX setX :x))
Is this set-and-get macro (or something similar) possible? I haven't been able to make it work.
(Updated with a second approach -- see below the second horizontal rule -- as well as some explanatory remarks re: the first one.)
I wonder if this might be a step in the right direction:
(defmacro reify-from-maps [iface implicits-map emit-map & ms]
`(reify ~iface
~#(apply concat
(for [[mname & args :as m] ms]
(if-let [emit ((keyword mname) emit-map)]
(apply emit implicits-map args)
[m])))))
(def emit-atom-g&ss
{:set-and-get (fn [implicits-map gname sname k]
[`(~gname [~'this] (~k #~(:atom-name implicits-map)))
`(~sname [~'this ~'v]
(swap! ~(:atom-name implicits-map) assoc ~k ~'v))])})
(defmacro atom-bean [iface a & ms]
`(reify-from-maps ~iface {:atom-name ~a} ~emit-atom-g&ss ~#ms))
NB. that the atom-bean macro passes the actual compile-time value of emit-atom-g&ss on to reify-from-maps. Once a particular atom-bean form is compiled, any subsequent changes to emit-atom-g&ss have no effect on the behaviour of the created object.
An example macroexpansion from the REPL (with some line breaks and indentation added for clarity):
user> (-> '(atom-bean HugeInterface data
(set-and-get setX getX :x))
macroexpand-1
macroexpand-1)
(clojure.core/reify HugeInterface
(setX [this] (:x (clojure.core/deref data)))
(getX [this v] (clojure.core/swap! data clojure.core/assoc :x v)))
Two macroexpand-1s are necessary, because atom-bean is a macro which expands to a further macro call. macroexpand would not be particularly useful, as it would expand this all the way to a call to reify*, the implementation detail behind reify.
The idea here is that you can supply an emit-map like emit-atom-g&ss above, keyed by keywords whose names (in symbolic form) will trigger magic method generation in reify-from-maps calls. The magic is performed by the functions stored as functions in the given emit-map; the arguments to the functions are a map of "implicits" (basically any and all information which should be accessible to all method definitions in a reify-from-maps form, like the name of the atom in this particular case) followed by whichever arguments were given to the "magic method specifier" in the reify-from-maps form. As mentioned above, reify-from-maps needs to see an actual keyword -> function map, not its symbolic name; so, it's only really usable with literal maps, inside other macros or with help of eval.
Normal method definitions can still be included and will be treated as in a regular reify form, provided keys matching their names do not occur in the emit-map. The emit functions must return seqables (e.g. vectors) of method definitions in the format expected by reify: in this way, the case with multiple method definitions returned for one "magic method specifier" is relatively simple. If the iface argument were replaced with ifaces and ~iface with ~#ifaces in reify-from-maps' body, multiple interfaces could be specified for implementation.
Here's another approach, possibly easier to reason about:
(defn compile-atom-bean-converter [ifaces get-set-map]
(eval
(let [asym (gensym)]
`(fn [~asym]
(reify ~#ifaces
~#(apply concat
(for [[k [g s]] get-set-map]
[`(~g [~'this] (~k #~asym))
`(~s [~'this ~'v]
(swap! ~asym assoc ~k ~'v))])))))))
This calls on the compiler at runtime, which is somewhat expensive, but only needs to be done once per set of interfaces to be implemented. The result is a function which takes an atom as an argument and reifies a wrapper around the atom implementing the given interfaces with getters and setters as specified in the get-set-map argument. (Written this way, this is less flexible than the previous approach, but most of the code above could be reused here.)
Here's a sample interface and a getter/setter map:
(definterface IFunky
(getFoo [])
(^void setFoo [v])
(getFunkyBar [])
(^void setWeirdBar [v]))
(def gsm
'{:foo [getFoo setFoo]
:bar [getFunkyBar setWeirdBar]})
And some REPL interactions:
user> (def data {:foo 1 :bar 2})
#'user/data
user> (def atom-bean-converter (compile-atom-bean-converter '[IFunky] gsm))
#'user/atom-bean-converter
user> (def atom-bean (atom-bean-converter data))
#'user/atom-bean
user> (.setFoo data-bean 3)
nil
user> (.getFoo atom-bean)
3
user> (.getFunkyBar data-bean)
2
user> (.setWeirdBar data-bean 5)
nil
user> (.getFunkyBar data-bean)
5
The point is reify being a macro itself which is expanded before your own set-and-get macro - so the set-and-get approach doesn't work. So, instead of an inner macro inside reify, you need a macro on the "outside" that generates the reify, too.
Since the trick is to expand the body before reify sees it, a more general solution could be something along these lines:
(defmacro reify+ [& body]
`(reify ~#(map macroexpand-1 body)))
You can also try to force your macro to expand first:
(ns qqq (:use clojure.walk))
(defmacro expand-first [the-set & code] `(do ~#(prewalk #(if (and (list? %) (contains? the-set (first %))) (macroexpand-all %) %) code)))
(defmacro setter [setterf kw] `(~setterf [~'this ~'v] (swap! ~'data assoc ~kw ~'v)))
(defmacro getter [getterf kw] `(~getterf [~'this] (~kw #~'data)))
(expand-first #{setter getter}
(reify HugeInterface
(getter getX :x)
(setter setX :x)))