【问题标题】:How to avoid additional parenthesis level on each macro recursion in Clojure如何避免 Clojure 中每个宏递归的附加括号级别
【发布时间】:2015-11-15 20:12:12
【问题描述】:

我有这个递归宏 m1,它被宏 m1-do 调用。目的是生成一些函数调用。

(defmacro m1 [fname x]
  (if (= (count x) 1)
    (let [a0 (first x)]
      `(~fname ~a0))
    (let [[a0 & arest] x]
      `((~fname ~a0) (m1 ~fname ~arest)))))

(defmacro m1-do [fname x]
  `(do (m1 ~fname ~x)))

这就是我想要达到的结果:

(m1-do f1 (45 98 122 143 215)) =>
(do (f1 45) (f1 98) (f1 122) (f1 143) (f1 215))

但相反,我在每次递归时都会得到一个额外的括号级别。第一个结果已经有太多了:

user=> (clojure.walk/macroexpand-all '(m1-do f1 (45 98)))
(do ((f1 45) (f1 98)))
user=> (clojure.walk/macroexpand-all '(m1-do f1 (45 98 122)))
(do ((f1 45) ((f1 98) (f1 122))))
user=> (clojure.walk/macroexpand-all '(m1-do f1 (45 98 122 143)))
(do ((f1 45) ((f1 98) ((f1 122) (f1 143)))))
user=> (clojure.walk/macroexpand-all '(m1-do f1 (45 98 122 143 215)))
(do ((f1 45) ((f1 98) ((f1 122) ((f1 143) (f1 215))))))

问题似乎是每次调用都会返回一个列表,其中添加了另一对(),我还尝试开发一些flattening 函数并在宏中使用它,但没有成功。

数字只是更复杂的真实内容的占位符。

【问题讨论】:

  • 我已经看到了这个使用 cons 的答案:stackoverflow.com/a/5261744/1431660 我无法让它与 cons 一起工作,因为我遇到了引用/取消引用的问题。
  • 我编辑了示例并在代码行 4 中删除了一级括号,但这并没有太大帮助。

标签: recursion clojure macros lisp


【解决方案1】:

你可以用一个非常简单的非递归宏来做到这一点:

(defmacro m1-do [fname coll]
  `(do ~@(map (partial list fname) coll)))

您可以使用cons 做同样的事情:

(defmacro m1-do [fname coll]
  (cons 'do (map (partial list fname) coll)))

两个版本完全相同,产生欲望输出:

(macroexpand '(m1-do f1 (45 98 122 143 215)))
; => (do (f1 45) (f1 98) (f1 122) (f1 143) (f1 215))

【讨论】:

    猜你喜欢
    • 2012-04-03
    • 2019-03-31
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 2019-10-20
    • 1970-01-01
    • 2021-05-13
    • 1970-01-01
    相关资源
    最近更新 更多