I want to program a macro in clojure. The macro is called like this (FORI from to task) e.g. (FORI 1 10 (println i)) and should print the numbers from 1 to 10. So far i have
(defmacro FORI [from to task]
`(let [i# (range ~from ~to)]
~task))
I don´t know how do get the list i# into the (print i).
Thanks for help.
You can use any symbol in hygienic forms if you unquote their quoted form:
(defmacro fori [from to task]
`(doseq [~'i (range ~from ~to)]
~task))
So here in the expanded form, symbol i will be substituted without change.
Note, using fixed symbols in macros is usually not a good practice, because now i will shadow other vars with the same name.
Related
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.
Here's my failed attempt:
(defmacro until
[condition body setup increment]
`(let [c ~#condition]
(loop [i setup]
(when (not c)
(do
~#body
(recur ~#increment))))))
(def i 1)
(until (> i 5)
(println "Number " i)
0
(inc i))
I get: CompilerException java.lang.RuntimeException: Can't let qualified name: clojure-noob.core/c
I am expecting this output:
Number 1
Number 2
Number 3
Number 4
Number 5
What's wrong?
There are a few issues with the macro:
You need to generate symbols for bindings inside macros. A convenient way to do this is suffix the names with #. Otherwise the bindings in your macros could overshadow bindings elsewhere in your code.
Some of the macro inputs were unnecessarily spliced when unquoted i.e. ~# instead of ~
Here's a version of the macro that will compile/expand:
(defmacro until [condition body setup increment]
`(let [c# ~condition]
(loop [i# ~setup]
(when-not c#
~body
(recur ~increment)))))
But this will loop forever in your example because condition is only evaluated once and i's value would never change anyway. We could fix that:
(defmacro until [condition body increment]
`(loop []
(when-not ~condition
~body
~increment
(recur))))
And we need to make i mutable if we want to change its value:
(def i (atom 1))
(until (> #i 5)
(println "Number " #i)
(swap! i inc))
;; Number 1
;; Number 2
;; Number 3
;; Number 4
;; Number 5
But now until is starting to look a lot like the complement of while, and its extra complexity doesn't seem beneficial.
(defmacro until [test & body]
`(loop []
(when-not ~test
~#body
(recur))))
This version of until is identical to while except the test is inverted, and the sample code above with the atom still behaves correctly. We can further simplify until by using while directly, and it'll ultimately expand to the same code:
(defmacro until [test & body]
`(while (not ~test) ~#body))
Change the let line too:
...
`(let [c# ~#condition]
...
Then rename all references of c to c#. The postfix # generates a unique, non-namespaced-qualified identifier to ensure that the symbol created by the macro doesn't clash with any existing symbols in the context that the macro expands into. Whenever you bind a symbol in a quoted form, you should be using # to prevent collisions, unless you have a good reason to not use it.
Why is this necessary in this case? I can't remember exactly the reason, but if I recall correctly, any symbols bound in a syntax quoted form (`()) are namespace qualified, and you can't use a let to create namespace qualified symbols.
You can recreate the error by typing:
(let [a/a 1]
a/a)
I have a macro defprinter where I can define functions that: get a value in a dic based on destructuring + print that variable.
This looks like:
(defmacro defprinter [name pattern]
(list 'defn name [pattern] '(prn to-print)))
So I can do something like (defprinter print-lemons {to-print :lemons}) and then (print-lemons {:lemons "lemons"}) and it will print the correct thing (and I can define printers with any kind of destructuring on the first argument).
But now I want to give the option of that function maybe knowing how to print with a color as well, such as, if the symbol color is defined, it should do (prn color "-colored " to-print), but else just (prn color).
So, the function generated by (defprinter print-lemons {to-print :lemons}) should work the same as above, while (defprinter print-lemons {to-print :lemons, color :color}) would write a function that performs the colored version.
Moreover, I want the same effect if I do
(let [color "black"] (defprinter print-lemons {to-print :lemons})) or (def color "black") (defprinter print-lemons {to-print :lemons}).
Is that possible?
I've tried writing it the following way:
(defmacro defprinter [name pattern]
(list 'defn name [pattern]
'(try (eval '(prn (str color "-colored " to-print)))
(catch java.lang.RuntimeException _
(prn to-print)))))
In my understanding the function the macro will write will try to eval the expression at runtime, fail with a RuntimeException if color is not defined and then execute the (prn to-print). And even though it would check for the existence of color at runtime, to-print (which always need to exist for that function) would be checked at compile time when the macro expands.
But what happens here is that I always get a RuntimeException, even when color is defined (even if I leave only to-print on the eval statement, it can't find it but the clause in the catch works fine). Seems like the symbol isn't being resolved as I would expect during eval, but I can't think of any other way to achieve this.
Any suggestions?
First off, it probably makes sense to split apart the two concerns you're working with here: defining a function, and determining how to print based on what vars/locals are available. Making macros as simple as possible tends to make it easier to figure out what's going on.
When deciding what to print, you really have 3 cases:
color is a local
color is a var (or class, I guess?)
color is undefined
&env is a useful and rarely-used tool (only available within macros) that lets you take a look at what's available as a local.
And resolve lets you look at what vars there are with that name.
So in this example, there are 3 potential expressions that could make up the body of the function defined with def-color-printer:
(defn make-print-expression [env]
(if (contains? env 'color)
`(prn (str ~'color "-colored " ~'to-print))
(if-let [color (resolve 'color)]
`(prn (str #~color "-colored " ~'to-print))
`(prn ~'to-print))))
(defmacro def-color-printer [name pattern]
(list `defn name [pattern]
(make-print-expression &env)))
(def-color-printer print-limes {to-print :limes})
(let [color "green"]
(def-color-printer print-limes-color-with-local {to-print :limes}))
(def color "greyish")
(def-color-printer print-limes-color-with-var {to-print :limes})
(print-limes {:limes "limes!"})
;=> "limes!"
(print-limes-color-with-local {:limes "limes!"})
;=> "green-colored limes!"
(print-limes-color-with-var {:limes "limes!"})
;=> "greyish-colored limes!"
I also wrote a blog about Clojure's quoting in case the syntax-quoting syntax is unfamiliar.
the resolve function will likely help you out with this. It returns the thing a symbol represents in the current namespace, or it returns nil. You can feed it to an if expression:
user> (resolve 'asdf)
nil
user> (if (resolve 'asdf) :defined :not-defined)
:not-defined
Remember to quote the symbol you want to resolve in the test.
I am working through Clojure for the Brave and True. In the chapter on macros there is this exercise:
Write a macro that defines an arbitrary number of attribute-retrieving functions using one macro call. Here’s how you would call it:
(defattrs c-int :intelligence
c-str :strength
c-dex :dexterity)
What these functions do is retrieve a value from a map. For example given: (def character {:name "Travis", :intelligence 20, :strength 23, :dexterity 13})
The result of (c-int character) would be 20 of course such a function could easily be defined as (def c-int #(:intelligence %))
This is the solution I came up with to the problem:
(defmacro defattrs
[& attributes]
`(let [attribute-pairs# (partition 2 (quote ~attributes))]
(map (fn [[function-name# attribute-key#]]
(def function-name# #(attribute-key# %)))
attribute-pairs#)))
The problem I am having is that def uses the generated symbol name instead of what it resolves to to define the function (which in hindsight makes sense given the usage of def). My attempts to use expressions with defining functions such as:
(let [x ['c-int :intelligence]]
(def (first x) #((second x) %)))
Have resulted in this error: CompilerException java.lang.RuntimeException: First argument to def must be a Symbol, compiling:(/tmp/form-init5664727540242288850.clj:2:1)
Any ideas on how I can achieve this?
There are ordinary manipulations that you do with the attributes parameter that don't need to be generated as forms:
splitting the attributes into attribute-pairs; and
defining the function to generate a def form for each pair.
Applying the above to your code, we get ...
(defmacro defattrs [& attributes]
(let [attribute-pairs (partition 2 attributes)]
(map (fn [[function-name attribute-key]]
`(def ~function-name #(~attribute-key %)))
attribute-pairs)))
The scope of the back-quote is restricted to the def we wish to generate.
The values of the function-name and attribute-key parameters of the function are inserted into the def form.
There is one problem remaining.
The result of the map is a sequence of def forms.
The first one will be interpreted as a function to
apply to the rest.
The solution is to cons a do onto the front of the sequence:
(defmacro defattrs [& attributes]
(let [attribute-pairs (partition 2 attributes)]
(cons 'do
(map (fn [[function-name attribute-key]]
`(def ~function-name ~attribute-key))
attribute-pairs))))
I've also abbreviated #(~attribute-key %) to the equivalent ~attribute-key within the back-quoted form.
Let's see what the expansion looks like:
(macroexpand-1 '(defattrs dooby :brrr))
;(do (def dooby :brrr))
Looks good. Let's try it!
(defattrs gosh :brrr)
(gosh {:brrr 777})
;777
It works.
You have found the use-case for the back-quote and tilde. Just try this:
(let [x ['c-int :intelligence]]
(eval `(def ~(first x) #(~(second x) %))))
(def character {:name "Travis", :intelligence 20, :strength 23, :dexterity 13})
(c-int character) => 20
The back-quote is similar to the single-quote in that it makes the next form into a data structure of lists, symbols, etc. The difference is that the data structure is intended to be used as a template, where internal bits can be substituted using the tilde. The cool part is that the tilde doesn't just substitute items, but works for live code that can be any arbitrary Clojure expression.
I want to write a macro (my-dotimes [x init end] & body) that computes the value of body for x going from init to end-1 in increments of 1. Here you again have to make sure to avoid the "variable capture problem". It should work like this:
user=> (my-dotimes [x 0 4] (print x))
0123nil
my code is :
(defmacro my-dotimes [[x initial end] & body]
`(loop [i# ~initial]
(when (< i# ~end)
~#body
(recur (inc i#))))))
but when I use macroexpand to check it and find:
user=> (macroexpand '(my-dotimes [x 0 4] (println x)))
(loop* [i__4548__auto__ 0] (clojure.core/when (clojure.core/<i__4548__auto__ 4)
(println x)
(recur (clojure.core/inc i__4548__auto__))))
I am wondering how to change
(println x) => (clojure.core/println i__4548__auto__)
Here, you supply the symbol that should be bound to the counter (here x), so you don't need to use gensyms.
Instead of using i#, just introduce the symbol given to you by the user of the macro.
You need gensyms when you introduce new symbols and don't want them to collide with existing symbols.
In Common Lisp, it would make sense to wrap the body with a binding from the user-supplied symbol to the current value of i, using (let ((,x ,i)) ,#body), because the user's code could change the value of the counter during iteration (which could be bad). But here I think you cannot mutate the variable directly, so you don't need to worry about that.
Your second example is:
(defmacro for-loop [[symb ini t change] & body]
`(loop [symb# ~ini]
(if ~t
~#body
(recur ~change))))
First problem: when you expand the body, which might be one or more form, you'll end-up with an if form with many branches instead of 2. You would have for example (if test x1 x2 x3 (recur ...)) if your body contains x1, x2 and x3. You need to wrap bodies in do expressions, with (do ~#body).
Now, the situation is not very different than before: you still have a symbol, given by the user, and you are responsible for establishing the bindings in the macro. Instead of using symb#, which creates a new symbol, completely distinct from symb, just use symb directly.
You could do this for example (untested):
(defmacro for-loop [[symb init test change] &body]
`(loop [~symb ~init]
(if ~test (do ~#body) (recur ~change))))
As long as you use the symbol provided by the caller of your macro, gensyms are not necessary. You need gensyms when you have to create a new variable in the generated code, which requires to have a fresh symbol. For example, you evaluate an expression only once and need a variable to hold its value:
(defmacro dup [expr]
`(let [var# ~expr]
[var# var#]))