Macroexpanding once the (make-placeholders 9)
expression I get this:
(for
[i__1862__auto__ (range 0 9)]
(defn-from
(str "_" i__1862__auto__)
{:placeholder true}
[& args]
(nth args i__1862__auto__)))
So defn-from
expects a string as first argument, but, because it is a macro, (str "_" i__1862__auto__)
is not evaluated and is thus past in as a list.
I played around with this for a while and came up with this:
(defmacro make-placeholders [n]
`(map eval
'~(for [cntr (range 0 n)]
`(defn ~(symbol (str "_" cntr))
{:placeholder true} [& args] (nth args ~cntr)))))
Macroexpanding (make-placeholders 3)
gives
(map eval
'((defn _0 {:placeholder true} [& args] (nth args 0))
(defn _1 {:placeholder true} [& args] (nth args 1))
(defn _2 {:placeholder true} [& args] (nth args 2))))
which is what I intended and evaluating this defines the functions _0
, _1
and _2
:
;=> (_0 1 2 3)
1
;=> (_1 1 2 3)
2
;=> (_2 1 2 3)
3
Ok, so this works, but I am still not sure its a good idea to do this.
First off eval is evil. Ok, it could also be done without eval
, but using do
instead (replace map eval
in my solution with do
). But you are possibly making your code hard to understand because you create functions that are not defined anywhere in your code. I remember that when I just started using Clojure I was looking through some library for a function and I couldn't find it. I started to think yikes, this guy must have defined a macro somewhere that defines the function I am looking for, how am I ever going to understand what's going on? If this is how people are using Clojure then it is going to be one hell of a mess and dwarf everything people have said about Perl... It turned out I was just looking at the wrong version - but you may be setting yourself and others up for some hardship.
Having said this, there may be appropriate uses for this. Or you could use something similar to generate code and put that into some file (then the source code would be available for inspection). Maybe somebody more experienced can chime in?