Reputation: 1007
It seems my understanding of macros is incomplete. How do I pass arguments to macros, and call them from functions. The seemingly simple code below code doesn't work.
(defmacro bar [arg]
(println (symbol? arg)))
(defn foo [arg]
(bar arg))
(foo 'baz) => nil
Upvotes: 3
Views: 1665
Reputation: 70235
For a macro to 'work' it needs to return code, generally as a list expression. So, for your intent you need to provide:
(defmacro bar (arg)
`(println (symbol? ,arg)))
(This uses quasiquote as a convenient notation for constructing lists.) At the point where you use bar
the use is expanded, by running the defmacro code, to produce that list. The list is then compiled. So for example:
(progn (bar 10))
is expanded into
(progn (println (symbol? 10))
which is compiled and then, later, you run the code and 'nil' gets printed. You'll note that (bar a)
will produce an error of 'a is not bound
' because the expansion is (println (symbol a))
whereby a
is evaluated, probably w/o a value. (bar 'a)
returns T
.
With this correct bar
macro, your function foo
, when compiled, will expand to:
(defun foo (x)
(println (symbol? x))
which computes (foo 'a)
and (foo 10)
properly.
Upvotes: 3
Reputation: 139411
A macro should generate code. It takes source expressions as an argument and creates new source.
Let's see:
user=> (defmacro bar [arg]
(println (symbol? arg)))
#'user/bar
user=> (bar 1)
false
nil
user=> (bar 'a)
false
nil
user=> (bar a)
true
nil
This is the expansion:
user=> (macroexpand-1 '(bar a))
true
It does not generate any useful code.
Upvotes: 4
Reputation: 1085
The macro is being evaluated when you define foo. If you define the foo function in the repl you notice that Clojure prints true.
user=> (defmacro bar [arg]
(println (symbol? arg)))
#'user/bar
user=> (defn foo [arg]
(bar arg))
true ; <= This is the print from your macro
; (it prints true, because arg is a symbol)
#'user/foo
You need to quote the body of the macro, otherwise it will be evaluated and because its return value is nil, foo will simply return nil.
(defmacro bar [arg]
`(println (symbol? ~arg)))
Upvotes: 6