繁体   English   中英

如何调用宏,并将参数传递给它

[英]How to call macro, and pass arguments to it

似乎我对宏的理解是不完整的。 如何将参数传递给宏,并从函数中调用它们。 代码下面看似简单的代码不起作用。

(defmacro bar [arg]
  (println (symbol? arg)))

(defn foo [arg]
  (bar arg))

(foo 'baz) => nil

定义foo时正在评估宏。 如果在repl中定义foo函数,则会注意到Clojure打印为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

你需要引用宏的主体,否则它将被评估,因为它的返回值是nil,foo将只返回nil。

(defmacro bar [arg]
   `(println (symbol? ~arg)))

宏应该生成代码。 它将源表达式作为参数并创建新的源。

  1. 你的宏采取什么来源?
  2. 你的宏生成了什么来源?

让我们来看看:

user=> (defmacro bar [arg]
         (println (symbol? arg)))   
#'user/bar
user=> (bar 1)
false
nil
user=> (bar 'a)
false
nil
user=> (bar a)
true
nil

这是扩展:

user=> (macroexpand-1 '(bar a))
true

它不会生成任何有用的代码。

要使宏“工作”,它需要返回代码,通常作为列表表达式。 所以,为了你的意图,你需要提供:

(defmacro bar (arg)
  `(println (symbol? ,arg)))

(这使用quasiquote作为构造列表的方便表示法。)在使用bar的位置,通过运行defmacro代码扩展使用以生成该列表。 然后编译该列表。 例如:

(progn (bar 10))

扩展到

(progn (println (symbol? 10))

这是编译后,然后,您运行代码并打印'nil'。 你会注意到(bar a)会产生' a is not bound '的错误,因为扩展是(println (symbol a)) ,其中a被评估,可能没有值。 (bar 'a)返回T

使用这个正确的bar宏,你的函数foo在编译时会扩展为:

(defun foo (x)
  (println (symbol? x))

它正确地计算(foo 'a)(foo 10)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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