I was practicing writing macros and I can't seem to get defn to work.
My syntax is: (my-define name parameter body)
Ignoring & parameters and recursive routines, How do I bind the name to a (fn[parameter] body)?
You will need to transform
(my-define <name> <args> <body>)
to
(def <name> (fn <args> <body>))
This is quite simple actually:
(defmacro my-define [name args body]
`(def ~name (fn ~args ~body)))
Related
I am trying to define a macro like this:
(defmacro foo-macro
"[name] is the name of the function to define
[meta-data] is the map that defines the meta-data of the function"
[name meta-data]
(let [vals (gensym "label-")]
`(def ~name
^#~meta-data
(fn [~vals] (eval nil)))))
However, I am getting this compilation error:
Unhandled java.lang.IllegalArgumentException Metadata must be
Symbol,Keyword,String or Map
I think this is normal. However, I am not sure how I can make such a macro to work, or if it is even possible.
Note: I do not want to use with-meta. Read the revision of the resolution of this other question to understand why: Clojure: issues getting the symbol of a function in a looping context.
The only reason why I would use with-meta, is if you have a way to make it return a non-AFunc identifier.
I'm sorry, but you do want to use with-meta, you just want to use it within your macro rather than within the code you return.
The form that you get by reading ^{:foo :bar} (fn []) is approximately the same as what you get by evaluating (with-meta `(fn [])), so that's what you want to do in your macro: evaluate the with-meta call while generating code.
(defmacro foo-macro
"[name] is the name of the function to define
[meta-data] is the map that defines the meta-data of the function"
[name meta-data]
(let [vals (gensym "label-")]
`(def ~name
~(with-meta `(fn [~vals] (eval nil))
meta-data))))
Calling (foo-macro fn-name {:foo "bar"}) should give you what you want: a function with (meta fn-name) returning {:foo "bar"} which, when printed, comes out something like #<user$fn_name user$fn_name#35df85a1>.
I am leaning macros in Clojure and have a question about macro expansion. In the repl, when I do this:
user=> (defmacro unless [pred a b] `(if (not ~pred) ~a ~b))
#'user/unless
user=> (macroexpand-1 '(unless (> 5 3) :foo :bar))
(if (clojure.core/not (> 5 3)) :foo :bar)
But when I do the same in a clj file:
(ns scratch-pad.core
(:gen-class))
(defmacro unless [pred a b]
`(if (not ~pred) ~a ~b))
(defn -main [& args]
(prn
(macroexpand-1 '(unless (> 5 3) :foo :bar))))
and run the code, I get this:
$ lein run
(unless (> 5 3) :foo :bar)
How do I get the code to print the same as the repl?
What's going on
This happens because of how the notion of the current namespace works in Clojure. macroexpand-1 expands its argument in the current namespace.
At the REPL, this will be user; you're defining the macro in the user namespace, then you call macroexpand-1 in that namespace and all is good.
In a :gen-class'd namespace, or indeed any other namespace, the compilation-time current namespace is that namespace itself. When you later call the code defined in this namespace, however, the then-current namespace will be whatever is appropriate at that point. That might be some other namespace as it gets compiled.
Finally, at your app's runtime, the default current namespace is user.
To see this, you could move the macro to a separate namespace also defining a function use-the-macro and calling this function at top level; the :gen-class'd namespace would then need to require or use the macro's namespace. Then lein run will print what you expect once (at the macro's namespace's compilation time) and the unexpanded form twice (when the macro's namespace is required by the main namespace and then when -main calls use-the-macro).
Solutions
The Clojure REPL controls the current namespace using binding; you can do the same:
(binding [*ns* (the-ns 'scratchpad.core)]
(prn (macroexpand-1 ...)))
You can also use syntax-quote instead of quote in -main:
(defn -main [& args]
(prn (macroexpand-1 `...)))
^- changed this
Of course if symbols other than unless were involved, you'd have to decide whether they should be namespace-qualified in the output and possibly prefix them with ~'. This is the point though -- syntax-quote is good for producing mostly "namespace-independent" code (which is what makes it so great for writing macros, besides the convenient syntax).
Another possible "fix" (tested on Clojure 1.5.1) is adding an in-ns call to -main:
(defn -main [& args]
(in-ns 'scratchpad.core)
(prn (macroexpand-1 '...)))
^- no change here this time
As with binding, this way you're actually getting the expansion of your original form in your original namespace.
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
I have two macros. The first one takes a symbol as the only parameter (because it's passed to def, which needs a symbol). The second function takes a list of symbols and should call the first with each symbol individually.
(defmacro m1 [s]
'(let [f# ... dynamic function definition ...]
(def ~s f#))
The second macro should take a list of symbols and pass them to the first, but I can't get it to work. The best I could come up with was the following:
(defmacro m2 [symbols]
`(for [s# ~symbols] (eval (read-string (str "(name.of.current.namespace/m1 " s# ")")))))
which forces the s# to be evaluated before it is passed to the first macro. It is also invoked with a list of strings, rather than a list of symbols.
This is useful for a library which I am using for which all of the functions in the library takes the same two first parameters. I am trying to create wrapper functions, in my namespace, for some of the functions, which automatically provides the first two parameter values which are common to all of them.
Any ideas to improve this?
Usually when you ask how to get two macros to cooperate, the answer is to not make them both macros. I think my blog post on macro-writing macros will help clarify. For this particular situation I'd probably combine two suggestions from the comments:
(defmacro build-simpler-functions [& names]
(cons 'do
(for [name names]
`(def ~(symbol (str "simple-" name))
(partial ~name 5 10))))) ; if you always pass 5 and 10
(build-simpler-functions f1 f2)
This expands to
(do
(def simple-f1 (clojure.core/partial f1 5 10))
(def simple-f2 (clojure.core/partial f2 5 10)))
which looks like basically what you want.
Edit: if the args you "always" pass are different for each function, you can do this:
(defmacro build-simpler-functions [& names]
(cons 'do
(for [[name & args] names]
`(def ~(symbol (str "simple-" name))
(partial ~name ~#args)))))
(build-simpler-functions [f1 5 10] [f2 "Yo dawg"]) ; expansion similar to the previous
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)))