3

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

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

(defn foo [arg]
  (bar arg))

(foo 'baz) => nil
4

3 回答 3

6

定义 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)))
于 2013-03-16T12:14:44.243 回答
4

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

  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

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

于 2013-03-16T11:28:53.967 回答
3

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

(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可能是 w/oa 值。 (bar 'a)返回T

使用这个正确bar的宏,您的函数foo在编译后将扩展为:

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

哪个计算(foo 'a)正确(foo 10)

于 2013-03-16T16:13:45.400 回答