I can "generate" a def with a macro.
(defmacro my-def [my-name]
`(def ~my-name 42))
(my-def a)
a; => 42
If I try to do something similar with a list
(defmacro my-defs [my-names]
`(do
~#(for [name# my-names]
`(def ~name# 42))))
(my-defs (a b c))
(macroexpand '(my-defs (a b c))); => (do (def a 42) (def b 42) (def c 42))
It works as long as I use a literal list as input. But as soon as I want to pass in a var
(def my-list '(a b c))
(macroexpand '(my-defs my-list)); => Don't know how to create ISeq from: clojure.lang.Symbol
I struggle to access the value of my-names. I can't use ~my-names as it is already used in a unquote-splice (~#) and would lead to an "Attempt[...] to call unbound fn".
What am I missing?
Do I need to use (var-get (resolve my-names))?
Do macros in these cases need to "detect" if the passed argument is a literal value or a var and act accordingly in order to work for both?
Or is it idiomatic to use eval to avoid this?
Addressing #Alan Thompson's question "[...] why [do] you want to do this?": I have a specification (a deeply nested map) of "resources" and it would be rather handy to have a macro generate defs (records) for these resources in order to use them down the line. So I guess no reason out of the ordinary "It would DRY up things". :) At this time I found a way by wrapping my-names in an eval. The question that remains is: Is this idiomatic, or is there a better way?
generally you can't employ macro to generate code based on runtime value,
still your task doesn't require macro in clojure, since you can dynamically intern vars in namespaces:
(defn intern-vals [data]
(doseq [[var-name var-val] data]
(intern *ns* var-name var-val)))
user> (intern-vals {'some-val 10 'other-val 20})
;;=> nil
user> some-val
;;=> 10
user> other-val
;;=> 20
notice that this function interns values in the namespace it gets called from, thanks to *ns* dynamic var:
user> (ns a2)
a2> (user/intern-vals {'some-val "asd" 'other-val "xxx"})
;;=> nil
a2> some-val
;;=> "asd"
a2> user/some-val
;;=> 10
Macros play with symbols. When you call your macro with "my-names", that symbol goes straight into the macro, there's no lookup of the var as there would be in a function call. Then the macro says (for... and instead of a sequence there's a symbol!
As for what you should do... well, you may use resolve inside the macro, but then the macro will ONLY work if given a symbol.
Addressing #Alan Thompson's question "[...] why [do] you want to do
this?": I have a specification (a deeply nested map) of "resources"
and it would be rather handy to have a macro generate defs (records)
for these resources in order to use them down the line. So I guess no
reason out of the ordinary "It would DRY up things". :) At this time I
found a way by wrapping my-names in an eval. The question that remains
is: Is this idiomatic, or is there a better way?
I would make a single var that contains them all. And allow the macro caller to specify the var name they want. Thus making the macro "hygenic".
Is there any particular reason they have to be root vars?
The reason it doesn't work is the macro is passed the symbol my-list, not its value. So yes, you can eval it to find its value.
Considering that you are doing a (def my-list ...) first, why not make that the very def that declares your processed data struct? For example:
(def my-processed-set
(my-processing-macro '(a b c)))
or combining it
(defresources my-processed-resources '(a b c))
where defresources is your macro, and it binds the resultant set to the var referenced by the symbol passed in my-processed-resources
Then use them like (:resource-1 my-processed-resources)
Which brings you all the way back to just using a function.
(def my-processed-set
(my-processing-function '(a b c)))
data > functions > macros.
Related
What I am trying to achieve is to implement an abstract class with reify inside a macro, but the expressions that should return on expansion time would be supplied to the macro quoted:
(defmacro a-printable
[body]
`(reify Printable
(print [this g# pf# page#]
(if (= page# 0)
(do
~body ;; the supplied part
(Printable/PAGE_EXISTS))
(Printable/NO_SUCH_PAGE)))
(def exp '(do (.translate g (.getImageableX pf) (.getImageableY pf))
(.drawString g "foo" 10 10))) ;; the form to pass
(a-printable exp)
The proplem is that in the expression I pass, I want to use the automatic generated vars defined inside the macro and inside reify g#, pf#.
I tried to add the quoted expression with (ns-resolve *ns* g) (ns-resolve *ns* pf) but with no lack, I am not sure that is being resolved inside the macro.
The g is java.awt.Graphics which is an abstract class and the pf is java.awt.print.PageFormat, which is normal class with constructor.
Does anyone has any idea how to achieve that, or turn me to the correct direction?
I believe the trick is that if you don't want namespaced symbols in a macro, you can prefix them with ~', e.g. ~'g. Then I did the following other modifications to your macro:
Prefix the body parameter with & to make it variable length.
Splice the body into the macro
Remove the parenthesis around (Printable/PAGE_EXISTS) and (Printable/NO_SUCH_PAGE): Those are static variable values that you want to return, not function calls.
This is what the fixed macro looks like:
(defmacro a-printable
[& body]
`(reify Printable
(print [~'this ~'g ~'pf ~'page]
(if (= ~'page 0)
(do
~#body ;; Splice it!
Printable/PAGE_EXISTS)
Printable/NO_SUCH_PAGE))))
And this is how you create an instance. Note that I do not need to wrap the argument to the macro with do:
(def p (a-printable
(.translate g (.getImageableX pf) (.getImageableY pf))
(.drawString g "foo" 10 10)))
A note however: I am not sure it is a good practice to introduce new symbols, such as pf and g, but I cannot find the reference mentioning why that would be a bad practice. There are ways of achieving similar things to what is being asked in this question without resorting to macros. The version that does not use macros is not much longer:
(defn a-printable-fn [body-fn]
(reify Printable
(print [this g pf page]
(if (= ~'page 0)
(do
(body-fn this g pf page)
Printable/PAGE_EXISTS)
Printable/NO_SUCH_PAGE))))
(def p (a-printable-fn
(fn [this g pf page]
(.translate g (.getImageableX pf) (.getImageableY pf))
(.drawString g "foo" 10 10))))
user=> (def v-1 "this is v1")
user=> (def v-2 "this is v2")
user=> (defmacro m [v] (symbol (str "v-" v)))
user=> (m 1)
"this is v1"
user=> (m 2)
"this is v2"
user=> (let [i 2] (m i))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: v-i in this context, compiling:(NO_SOURCE_PATH:73:12)
Can I write a macro let both
(m 2)
and
(let [i 2] (m i))
get "this is v2" ?
This is possible without a macro:
(defn m [v] (var-get (resolve (symbol (str "v-" v)))))
(m 1) ;; => "This is v1"
(let [i 2] (m i)) ;; => "This is v2"
You can use a macro too if you want:
(defmacro m [v] `#(resolve (symbol (str "v-" ~v))))
A plain function seems much more likely to be what you want.
First, though, to address the original question, if you wanted to insist on using a macro, macros are regular functions that happen to be called at compile time, so you can look up a Var using its symbolic name and obtain its value using deref just like you could at (your application's, as opposed to your macro's) runtime:
(defmacro var-value [vsym] #(resolve vsym))
(def foo 1)
(var-value foo)
;= 1
(macroexpand-1 '(var-value foo))
;= 1
Note that the above 1 is the actual macroexpansion here. This is different to
(defmacro var-value [vsym] `#(resolve ~vsym))
in that the latter expands to a call to resolve, and so the lookup given that implementation is postponed to your app's runtime.
(macroexpand-1 '(var-value foo))
;= (clojure.core/deref (clojure.core/resolve foo))
So this code will just be inlined wherever you call the macro.
Of course the macro could also expand to a symbol – e.g.
(defmacro prefixed-var [suffix]
`(symbol (str "v-" ssuffix)))
will produce expansions like v-1 (for (prefixed-var 1)) etc.
Going back to the subject of the suitability of macros here, however, if you use a macro, all the information that you need to produce your expansion must be available at compile time, and so in general you cannot use the values of let / loop locals or function arguments in your expansion for the fundamental reason that they don't have any fixed value at compile time.1
Thus the cleanest approach would probably be to wrap a resolve call in defn and call the resulting function – although of course to know for sure, we'd need to know what problem you were trying to solve by introducing a macro that performs a Var lookup.
1 Except if statically assigned constant values, as in the example given in the question text; I'm assuming you're thinking of using runtime values of locals in general, not just those that whose initialization expressions are constant literals.
Why do I get the error:
IllegalArgumentException First argument to defn must be a symbol clojure.core/defn (core.clj:277)
When I try to define a function like this:
(defn (symbol "f[]") 1)
Or like this:
(defn (symbol "f") [] 1)
Why aren't those the equivalent of straight forward example below ?
(defn f [] 1)
This is esoteric I know: but it just occurred to me that I might want to name a function dynamically at some point. (No real use case here - just trying to understand Clojure's mind...)
When you pass arguments to a macro, they are not evaluated beforehand. Since defn is a macro, what you're passing it in those two cases are not equivalent.
You are mixing code and data. It is a very common mistake to do. Eg.
(+ 4 5) ; ==> 9
('+ 4 5) ; ==> Error
'+ evaluates to a symbol. It is not the same as the variable + that is code and evaluates for a function. It's easy to check by evaluating them:
+ ; ==> #<core$_PLUS_ clojure.core$_PLUS_#312aa7c>
'+ ; ==> +
defn is a macro that expands to def so your beef is with def. The reason (def (symbol "x") 5) doesn't work is because def happens at compile time. The first arguments is never evaluated, but used for all references to the same identifiers within the same namespace. An expression like (symbol "x") won't work pretty much because of the same reason + and '+ cannot be mixed. You can do this in compile time though:
(defmacro make-fun [name expression]
`(defn ~(symbol name) [] ~expression))
(macroexpand-1 '(make-fun "f" 1))
; ==> (clojure.core/defn f [] 1)
(make-fun "f" 1)
; ==> #'user/f
(f) ; ==> 1
So what is happening is that before the code runs (make-fun "f" 1) gets replaced with (clojure.core/defn f [] 1) and the runtime never ever sees where it came from. While this seems useful you still cannot use a binding or input to make your function:
(def fun-name "f")
(def fun-value 1)
(macroexpand-1 '(make-fun fun-name fun-value))
; ==> (clojure.core/defn fun-name [] fun-value)
Macros are just a way to simplify and abstract on syntax. If you always write a pattern that looks like (defn name [& args] (let ...) you can make the parts that differ bindings in a macro and shorten every place you use the abstraction with the new macro. It is a code translation service. In compile time the arguments are just the literal code that it is suppsoed to replace and you never have the luxury to see if a variable or expression has a certain value since you only knows about the code and never what they actually represent. Thus the errors usually arises in when the code in the end result runs.
In the end you can do anything in runtime with eval. I've seen eval being used in a sensible manner twice in my 19 year run as a professional programmer. You could do:
(defn make-fun [name value]
(eval `(defn ~(symbol name) [] ~value)))
(make-fun fun-name fun-value)
; #'user/f
(f)
; ==> 1
Now while this works you shouldn't do it unless this is some sort of tool to test or do something with code rather than it being a part of the code to be run as a service with the string coming in from a unsafe source. I would have opted for using dictionaries instead such that you do not update your own environment. Imagine if the input was make-fun or some other part of your code that would give the client control over your software.
The answer is what Josh said (defn is a macro; if it was a function then your code really would work in this way). You can define your own defn variation macro that would do what you want or just use eval:
(eval `(defn ~(symbol "f") [] 1))
; => #'user/f
(f)
; => 1
You really don't need to use eval.
You have hit the problem known as "turtles all the way down". Once you try to treat a macro like a function (perhaps passing it to map, for example), you find you cannot do it without writing another macro. The same applies to macro #2, etc.
Thus, you can't compose macros as well as you can compose functions. This is the genesis of the general advice, "Never use a macro when you can use a function."
In this case, defn is a macro, so you have no choice but to write another macro (def behaves the same way, even though it is a special form instead of a macro). Our new macro dyn-defn dynamically creates the function name from a list of strings:
(defn fun-1 [] 1)
(def fun-2 (fn [] 2))
; (def (symbol (str "fun" "-3")) (fn [] 3))
; => Exception: First argument to def must be a Symbol
(defmacro dyn-defn
"Construct a function named dynamically from the supplied strings"
[name-strs & forms]
(let [name-sym (symbol (str/join name-strs)) ]
(spyx name-sym)
`(defn ~name-sym ~#forms)))
(dyn-defn ["fun" "-3"]
[]
3)
with result:
*************** Running tests ***************
:reloading (tst.demo.core)
name-sym => fun-3 ; NOTE: this is evaluated at compile-time
Testing _bootstrap
-------------------------------------
Clojure 1.9.0 Java 1.8.0_161
-------------------------------------
Testing demo.core
Testing tst.demo.core
(fun-1) => 1 ; NOTE: these are all evaluated at run-time
(fun-2) => 2
(fun-3) => 3
Note that the function name is an argument to the defn macro, and must be a symbol, not a function call.
Note:
Correct, you can't tell by looking at it if a form is "calling" a function or a macro. In fact, many "build-in" features of Clojure are constructed from more fundamental parts of the language, whether macros like when (source code) or functions like into (source code).
My question is: how can I get the args list and expressions of a received function ?
I'm trying to do something like this:
(defn first-fn [[args exprs]]
(println "Args:" args)
(println "Exprs:" exprs))
(first-fn (fn [a b c] (println "something")))
So, first-fn would print:
Args: [a b c]
Exprs: (println "something")
My goal is to create a macro that can use the args list of the received function.
Thank you.
Edit:
Use case:
I'm using compojure https://github.com/weavejester/compojure
You can define routes like this:
(GET "/:id" [id] (body_here id))
But I would like to change the syntax to be:
(defn handler-fn [id] (body_here id))
...
(GET "/:id" handler-fn)
So the handler (body) can be extracted from the routes, and might be reused as well.
I tried to reuse compile-route https://github.com/weavejester/compojure/blob/master/src/compojure/core.clj#L172
(defmacro MY_GET [path fn-src]
(let [fn-fn (second fn-src)
arg-vec (nth fn-src 2)
forms (drop 3 fn-src)]
(compojure.core/compile-route :get path arg-vec forms)))
But when I call:
(MY_GET "/:id" handler-fn)
It says: Don't know how to create ISeq from: clojure.lang.Symbol
You cannot do this with functions, you directly need a macro to do this and even then it is not straight-forward. First, let's explain the difference: macros are basically evaluated at compile-time and the result of this evaluation is then evaluated at run-time. The interesting part is that the evaluation at compile-time gets the literal, unevaluated arguments to the macro as data and not, like normal functions would, the evaluated arguments at run-time. So, your approach cannot work, because at the time first-fn receives it's arguments (at run-time), they are already evaluated -- in your example, first-fn receives nil as arguments. Cf. the documentation at clojure-doc for a much better explanation.
Now, solving your request with a macro requires the macro to parse the arguments (remember: at compile time, code is data) that it receives -- i.e. in your example, it needs to parse the sequence (fn [a b c] (println "something")) that builds up the function call you hand over to it. Probably you would want to cover other cases besides the fn one (e.g. the # short-hand), that's what it makes the problem not straight-forward in the general case.
This parsing could in the end be handled by a normal function parsing, e.g. a sequence. So, try solving a different puzzle first: build a function parse-code-sequence that takes a sequence (that looks like the functions you would hand over) and returns the args and expr -- note the quote (') in front of fn.
user> (parse-code-sequence '(fn [a b c] (println "something")))
{args: [a b c], expr: (println "something")}
Some hints to this: in the example here, which is showing the most used case, the sequence just consists of three elements and you don't need the first one. But the general case is a little bit more complex, cf. the official documentation on fn.
A final remark: when you implement the macro, you need to think about what it resolves to -- just adding the print-statements is easy, but do you also want to evaluate the arguments normally (so your macro becomes something like a debugging aid) or do you want to do something else?
Update to reflect your use-case
Your MY-GET macro is not doing what you think it's doing.
Take a look at the arguments that the macro gets: why do you think it can magically retrieve the function definition of handler-fn, when all that you give as argument to MY_GET is the symbol/var handler-fn? You would need to retrieve the source, but this usually will not be possible (cf. this SO question on retrieving the source of a function definition).
You are also missing a backquote before the call to compile-route: you want the call to compile-route to happen at run-time, not at compile time. Currently, the result of the macro evaluation is the result of the call to compile-route (at compile-time). Take a look at macroexpand which would show you the result of the macro-expansion. Basically, you want the macro to return the call to compile-route.
I don't see any easy way that you could accomplish what you look for. The argument vector of a route definition is defining what needs to be handed over. Even if you extract that to a function definition, compojure still needs to know what to hand over to that function.
Here is an example of what you could do.
(ns xyz
(:require
[tupelo.core :as t]
))
(t/refer-tupelo)
(spyx *clojure-version*)
(defmacro dissect [ fn-src ]
(let [fn-fn (first fn-src)
arg-vec (second fn-src)
forms (drop 2 fn-src) ]
(spyx fn-fn)
(spyx arg-vec)
(spyx forms)
; Here is the return value; ie the transformed code
`(defn my-fn
~arg-vec
(apply + ~arg-vec))))
; show the result
(newline)
(println
(macroexpand-1
'(dissect
(fn [a b c]
(println "the answer is")
42))))
; call it for real
(newline)
(dissect
(fn [a b c]
(println "the answer is")
42))
; use the generated function
(newline)
(spyx (my-fn 1 2 3))
with result:
*clojure-version* => {:major 1, :minor 8, :incremental 0, :qualifier nil}
fn-fn => fn
arg-vec => [a b c]
forms => ((println "the answer is") 42)
(clojure.core/defn tst.clj.core/my-fn [a b c] (clojure.core/apply clojure.core/+ [a b c]))
fn-fn => fn
arg-vec => [a b c]
forms => ((println "the answer is") 42)
(my-fn 1 2 3) => 6
Your project.clj needs the following to make spyx work:
:dependencies [
[tupelo "0.9.11"]
Given a list of names for variables, I want to set those variables to an expression.
I tried this:
(doall (for [x ["a" "b" "c"]] (def (symbol x) 666)))
...but this yields the error
java.lang.Exception: First argument to def must be a Symbol
Can anyone show me the right way to accomplish this, please?
Clojure's "intern" function is for this purpose:
(doseq [x ["a" "b" "c"]]
(intern *ns* (symbol x) 666))
(doall (for [x ["a" "b" "c"]] (eval `(def ~(symbol x) 666))))
In response to your comment:
There are no macros involved here. eval is a function that takes a list and returns the result of executing that list as code. ` and ~ are shortcuts to create a partially-quoted list.
` means the contents of the following lists shall be quoted unless preceded by a ~
~ the following list is a function call that shall be executed, not quoted.
So ``(def ~(symbol x) 666)is the list containing the symboldef, followed by the result of executingsymbol xfollowed by the number of the beast. I could as well have written(eval (list 'def (symbol x) 666))` to achieve the same effect.
Updated to take Stuart Sierra's comment (mentioning clojure.core/intern) into account.
Using eval here is fine, but it may be interesting to know that it is not necessary, regardless of whether the Vars are known to exist already. In fact, if they are known to exist, then I think the alter-var-root solution below is cleaner; if they might not exist, then I wouldn't insist on my alternative proposition being much cleaner, but it seems to make for the shortest code (if we disregard the overhead of three lines for a function definition), so I'll just post it for your consideration.
If the Var is known to exist:
(alter-var-root (resolve (symbol "foo")) (constantly new-value))
So you could do
(dorun
(map #(-> %1 symbol resolve (alter-var-root %2))
["x" "y" "z"]
[value-for-x value-for-y value-for z]))
(If the same value was to be used for all Vars, you could use (repeat value) for the final argument to map or just put it in the anonymous function.)
If the Vars might need to be created, then you can actually write a function to do this (once again, I wouldn't necessarily claim this to be cleaner than eval, but anyway -- just for the interest of it):
(defn create-var
;; I used clojure.lang.Var/intern in the original answer,
;; but as Stuart Sierra has pointed out in a comment,
;; a Clojure built-in is available to accomplish the same
;; thing
([sym] (intern *ns* sym))
([sym val] (intern *ns* sym val)))
Note that if a Var turns out to have already been interned with the given name in the given namespace, then this changes nothing in the single argument case or just resets the Var to the given new value in the two argument case. With this, you can solve the original problem like so:
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))
Some additional examples:
user> (create-var 'bar (fn [_] :bar))
#'user/bar
user> (bar :foo)
:bar
user> (create-var 'baz)
#'user/baz
user> baz
; Evaluation aborted. ; java.lang.IllegalStateException:
; Var user/baz is unbound.
; It does exist, though!
;; if you really wanted to do things like this, you'd
;; actually use the clojure.contrib.with-ns/with-ns macro
user> (binding [*ns* (the-ns 'quux)]
(create-var 'foobar 5))
#'quux/foobar
user> quux/foobar
5
Evaluation rules for normal function calls are to evaluate all the items of the list, and call the first item in the list as a function with the rest of the items in the list as parameters.
But you can't make any assumptions about the evaluation rules for special forms or macros. A special form or the code produced by a macro call could evaluate all the arguments, or never evaluate them, or evaluate them multiple times, or evaluate some arguments and not others. def is a special form, and it doesn't evaluate its first argument. If it did, it couldn't work. Evaluating the foo in (def foo 123) would result in a "no such var 'foo'" error most of the time (if foo was already defined, you probably wouldn't be defining it yourself).
I'm not sure what you're using this for, but it doesn't seem very idiomatic. Using def anywhere but at the toplevel of your program usually means you're doing something wrong.
(Note: doall + for = doseq.)