【问题标题】:How to call macro, and pass arguments to it如何调用宏,并将参数传递给它
【发布时间】:2013-03-16 10:48:43
【问题描述】:

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

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

(defn foo [arg]
  (bar arg))

(foo 'baz) => nil

【问题讨论】:

    标签: macros clojure lisp


    【解决方案1】:

    在定义 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)))
    

    【讨论】:

      【解决方案2】:

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

      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
      

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

      【讨论】:

      • 如果我理解正确,那么 foo 的定义将扩展为 (println (symbol?arg)) 将打印 true for (foo 'baz)。我在这里错过了什么?
      • @navgeet,不,您编写的宏不会扩展为 (println (symbol? arg))。宏只是一个函数,它必须返回扩展形式。如果您想获得您所描述的内容,您应该将宏的主体更改为 `(println (symbol? ~arg))。
      【解决方案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 被评估,可能没有值。 (bar 'a) 返回T

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-05-16
        • 1970-01-01
        • 2012-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-03
        相关资源
        最近更新 更多