【问题标题】:What is the idiomatic way to evaluate a modified argument in a Clojure macro?在 Clojure 宏中评估修改参数的惯用方法是什么?
【发布时间】:2015-03-03 11:04:51
【问题描述】:

想象一下,我的意图是修改传递给宏的 s 表达式的语法树,方法是修改语法树,然后评估修改后的参数。我可以执行以下操作:

(defmacro runargs [args]
  (eval (cons (first args) " buckeroo")))

(runargs (println "hi there"))

现在这不感觉惯用,因为我在我的代码中间敲了一个大的eval

现在我稍微修改一下,得出以下结论:

(defmacro runargs [args]
  `(~@(cons (first args) " buckeroo")))

(runargs (println "hi there"))

这解决了eval 的问题。但我仍然觉得这不是很地道。

我的问题是:在 Clojure 宏中评估修改参数的惯用方法是什么?

【问题讨论】:

  • 你能提供你想要的输出,包括 AST-wise 和打印的输出吗? (因为给定的代码不会打印buckeroo,而是b u c k e r o o,我不确定这是否是有意的。)
  • 我很抱歉。让我们假设这是有意的。
  • 使用宏的“诀窍”是清楚地了解宏展开后代码的外观。由此,您可以识别您正在尝试执行的操作的模板。一旦你有了它,那么宏的定义就相当简单了。在大多数情况下,您不希望宏评估参数 - 它更多的是在编译时将参数重新排列为新形式,然后在运行时进行评估。考虑如果参数是(inc x ) 而不是 println 和字符串 - 编译时 x 是什么? inc 应该何时发生?

标签: clojure macros arguments eval


【解决方案1】:

你给出的两个例子做了完全不同的事情。第一个是在宏扩展时间评估修改后的 s 表达式,这几乎肯定不是您想要的。

user=> (defmacro runargs-eval [args]
         (eval (cons (first args) " buckaroo")))
#'user/runargs-eval

user=> (macroexpand '(runargs-eval (println "hi there")))
  b u c k e r o o
nil

user=> (defmacro runargs [args]
         `(~@(cons (first args) " buckeroo")))
#'user/runargs

user=> (macroexpand '(runargs (println "hi there")))
(println \space \b \u \c \k \e \r \o \o)

如果您只是评估一个恰好包含对您的宏的调用的单个 s 表达式,但如果您正在编译使用您的宏的代码(如在lambda),宏扩展发生在编译时:

user=> (defn say-hello-eval [x] (runargs-eval (println x)))
  b u c k e r o o
#'user/say-hello-eval

user=> (say-hello-eval "hi there")
nil

user=> (defn say-hello [x] (runargs (println x)))
#'user/say-hello

user=> (say-hello "hi there")
  b u c k e r o o
nil

宏是简单的函数,它接受一个未计算的表达式,并返回一个修改后的未计算的表达式。如果您真的想将表达式作为宏扩展的一部分进行计算,这将是一种非常不寻常的情况 - 通常您的宏只会返回修改后的表达式,并让 Clojure 编译器在适当的时候处理它。

第二个示例中的语法引用实际上并不是必需的 - 语法引用的一般用例是当您将宏参数插入模板化表达式中时,该表达式包含应解析为命名空间中的某些内容的符号宏被定义。如果您的宏确实是 s 表达式的语法转换,那么您可以像操作任何其他 Clojure 数据结构一样将表达式作为数据进行操作:

(defmacro runargs [args]
  (cons (first args) " buckeroo"))

【讨论】:

    猜你喜欢
    • 2011-10-21
    • 1970-01-01
    • 2012-11-19
    • 1970-01-01
    • 2015-05-25
    • 2011-07-12
    • 2015-04-01
    • 2011-03-28
    • 1970-01-01
    相关资源
    最近更新 更多