【问题标题】:clojure macro unquote splicing list of function callsclojure 宏 unquote 拼接函数调用列表
【发布时间】:2017-09-23 02:01:37
【问题描述】:

我想通过写一个宏来写一个ACL模块,这个宏是检查宏中每个函数调用的结果,如果一个返回false,那么ACL会失败而不运行下面的函数调用。如果一个返回 true 并且仍有函数调用需要检查,那么检查以下直到最后一个。

(defmacro checks
  [head & tail]
  `(let [status# ~head]
     (if (and (true? status#)
              (seq '~tail))
       (checks ~@tail)
       status#)))

我会这样称呼这个宏:

(checks (module1 args) (module2 args))`

但是对于宏定义中的(check ~@tail),这将失败。问题是我想取消引用拼接列表,但不调用列表中的每个函数。

【问题讨论】:

  • 只是一个提示,不要使用反引号来格式化大段代码。通过突出显示并按 ctrl+k 将其缩进四个空格。
  • and 宏不会做同样的事情吗?
  • 谢谢你们的cmets。

标签: clojure macros


【解决方案1】:

我找到了解决这个问题的方法:

(defmacro checks
  [head & tail]
  (let [sym (gensym)]
    `(let [~sym ~head]
       (if ~sym
         ~(if tail
            `(checks ~@tail)
            sym)
         ~sym))))

(checks ~@tail) 表单的外部再次使用语法取消引用。

【讨论】:

  • mine 更干净。它只是 and 的另一个名字,没有零值。
【解决方案2】:

问题在于,即使没有参数,您也正在生成递归调用宏的代码。

(macroexpand-1 '(checks 1))
=>
(clojure.core/let
 [status__1973__auto__ 1]
 (if
  (clojure.core/and (clojure.core/true? status__1973__auto__) (clojure.core/seq (quote nil)))
  (user/checks)
  status__1973__auto__))

内部宏调用失败,因为它至少需要一个参数。无论您向宏提供多少参数,它的扩展最终都会产生失败的调用。

在生成对checks的递归调用之前,您需要确定tail中是否有任何内容:

(defmacro checks
  [head & tail]
  (if-not tail
    head
    `(let [status# ~head]
       (if (true? status#)
         (checks ~@tail)
         status#))))

现在

(macroexpand-1 '(checks 1))
=> 1

(checks 1)
=> 1

(macroexpand-1 '(checks 1 2 3))
=>
(clojure.core/let
 [status__2010__auto__ 1]
 (if (clojure.core/true? status__2010__auto__) (user/checks 2 3) status__2010__auto__))

还有

(checks 1 2 3)
=> 1
(checks true true 3)
=> 3

正如@PiotrekBzdyl 的评论所暗示的,这只是一个and 宏,它将true 以外的任何内容都视为错误。

【讨论】:

  • 谢谢。此宏将生成不正确的递归调用。
猜你喜欢
  • 2011-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-12
  • 2011-05-27
相关资源
最近更新 更多