简体   繁体   中英

How to call macro, and pass arguments to it

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

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)))

A macro should generate code. It takes source expressions as an argument and creates new source.

  1. what source does your macro take?
  2. what source does your macro generate?

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.

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/oa 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM