Clojure - 宏中的 let 不起作用
Posted
技术标签:
【中文标题】Clojure - 宏中的 let 不起作用【英文标题】:Clojure - a let in a macro won't work 【发布时间】:2013-02-13 19:59:43 【问题描述】:我创建了一个宏,它创建了一个名为 dispatcher
的宏,它具有 3 个关联函数 get-dispatcher
、set-dispatcher
和 call-dispatcher
,以与调度程序一起工作(它们获得一个调度函数,添加一个或调用一个)。一切正常!但是,现在我想自动创建相关的函数名称,因此我将宏的所有这些内部结构放入定义了该简单构造函数的 let
中。请注意,在下面的代码中,只有 get-
函数的名称是使用该自动化构造的。 set-
和 call-
的名称创建仍然具有手动气味。
(defmacro create-dispatcher [name]
;creates a set of dispatching functions tagged
`(do
;define dispatcher
(def ~(symbol name) ~(atom ))
(let
[name-w-prefix (fn [x] (~(symbol (str x "-" name))))]
; -- define getter
(defn (name-w-prefix "get")
"get-dispatcher [tag]: get a dispatcher fn by tag"
(~'[] (println "no tag is provided for '" ~(str name) "' dispatcher"))
(~'[tag]
(do
(println "dispatcher '" ~(str name) "' called with '" ~'tag "' tag")
; return the tagged dispatcher
( (keyword ~'tag) @~(symbol name) )))
)
; -- define caller
(defn ~(symbol (str "call-" name))
"get-dispatcher [tag & args]: call a dispatcher fn by tag and apply to the args"
~'[tag & args]
(apply (~(symbol (str "get-" name)) ~'tag) ~'args)
)
; -- define setter
(defn ~(symbol (str "set-" name))
~'[tag fn]
"add-dispatcher [tag fn]: add a dispatcher fn associated with the tag"
(swap! ~(symbol name) assoc (keyword ~'tag) ~'fn)
)
)
; -- report
(println "created dispatcher set for '" ~(str name) "' ok!")
))
但是,有一个问题。 let
语句绑定中的 name-w-prefix
会导致错误。我该如何解决?
(也欢迎任何关于改进的建议,因为我是新手,这几乎是我在 Clojure 中写的第一件事)
【问题讨论】:
【参考方案1】:宏中的所有符号都在当前命名空间中解析,并期望计算为 var。您可以引用 name-w-prefix
符号,但这可能会与宏扩展期间传入宏的符号发生冲突。因此,Clojure 提供了一种特殊的语法,用于在语法引用形式中生成符号 - 只需将 #
附加到符号末尾,Clojure 就会将其视为带引号的自动生成符号。因此,在这种情况下,将出现的 name-w-prefix
替换为 name-w-prefix#
就可以了。
退后一步,看看你的总体目标是什么,我认为你应该将name-w-prefix
定义移出语法引号,然后使用syntax-escape 来调用它。否则,你会得到更多的错误,因为defn
需要一个符号,所以一旦扩展宏必须生成一个defn
表单,其中第二项是符号。大致如下:
(defmacro create-dispatcher [name]
(let [name-w-prefix #(symbol (str % "-" name))]
`(do
(def ~(symbol name) (atom ))
(defn ~(name-w-prefix "get")
([] (println "no tag provided"))
([tag#] (println "called with tag" tag#))))))
请注意,根据我上面所说的内容,我已将 defn
正文中的 ~'[tag]
更改为 [tag#]
。
【讨论】:
感谢您的解释!不知道..但我做到了,现在它抱怨函数定义中的x
符号..
查看编辑。我认为您对语法引号内部和外部的内容有点困惑。
是的,看起来像!例如,我认为既然这都是关于 AST 的,我可以像 ~(expr)
从函数中返回,它会替换调用者,就好像在这里显式写的一样。但看起来~
的工作方式不同......也感谢~'
-> #
的建议!现在我已经修复了所有的宏,它工作正常!以上是关于Clojure - 宏中的 let 不起作用的主要内容,如果未能解决你的问题,请参考以下文章
LibreOffice Calc Goal Seek 在基本宏中不起作用