拿这个(简化的)例子:
(defmacro make [v & body]
`(let [~'nv ~(some-calc v)]
~(map #(if (= % :value) 'nv %) body)))
Run Code Online (Sandbox Code Playgroud)
现在这个符号nv是硬编码的.有没有办法以某种方式gensym nv并仍然能够在地图功能中使用它?
顺便说一句,这实际上是一个照应的宏吗?
答案包含在问题中:gensym就像 Clojure 没有 auto-gensyms 一样使用。
(defmacro make [v & body]
(let [value-sym (gensym)]
`(let [~value-sym ~(some-calc v)]
~@(replace {:value value-sym} body))))
Run Code Online (Sandbox Code Playgroud)
请注意,我不确定您是否真的想要~或~@在这里 - 这取决于是否body应该是在 中执行的表达式序列let,或者单个函数调用的参数序列。但~@会更加直观/正常,所以这就是我要猜测的。
这个宏是否是照应有点值得怀疑:肯定是引入nv到调用范围中,但它基本上是无意的,所以我会说不。在我的修订版本中,我们不再引入nv或类似的内容,但我们“神奇地”替换:value为v. 不过,我们只在主体的最顶层执行此操作,因此这不像引入真正的范围 - 我想说这更像是让客户端的代码在极端情况下意外中断。
有关这种欺骗行为如何突然出现的示例,请想象 的元素之一body是(inc :value)。它不会被宏替换,并且会扩展为(inc :value),但永远不会成功。因此,我建议使用真正的照应宏,它引入了符号的真实范围。就像是
(defmacro make [v & body]
`(let [~'the-value ~(some-calc v)]
~@body))
Run Code Online (Sandbox Code Playgroud)
然后调用者可以the-value在他们的代码中使用,它的行为就像一个真正的常规本地绑定:您的宏通过魔法引入它,但它没有任何其他特殊技巧。
| 归档时间: |
|
| 查看次数: |
737 次 |
| 最近记录: |