Macros Clojure-一个宏中的let';行不通
我创建了一个宏,该宏创建了一个命名的Macros Clojure-一个宏中的let';行不通,macros,clojure,let,Macros,Clojure,Let,我创建了一个宏,该宏创建了一个命名的调度程序,其中包含3个关联函数获取调度程序,设置调度程序和调用调度程序,以与调度程序一起工作(它们获取调度函数,添加一个或调用一个)。一切都很好!但是,现在我想自动创建相关的函数名,因此我将把宏的所有这些内部内容放入一个let,它定义了简单的构造函数。请注意,在下面的代码中,只有get-函数的名称是使用该自动化构造的。set-和call-的名字创建仍然有手动的味道 (defmacro create-dispatcher [name] ;creates a
调度程序,其中包含3个关联函数获取调度程序,设置调度程序和调用调度程序,以与调度程序一起工作(它们获取调度函数,添加一个或调用一个)。一切都很好!但是,现在我想自动创建相关的函数名,因此我将把宏的所有这些内部内容放入一个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中写的第一件事,因此欢迎您提供任何改进建议)宏中的所有符号都在当前名称空间中解析,并期望计算为变量。您可以引用name-w-prefix
符号,但这可能会与在宏扩展期间传递给宏的符号发生冲突。因此,Clojure提供了一种特殊的语法,用于生成符号的语法引用形式——只需在符号末尾添加一个#
,Clojure就会将其视为一个引用的、自动生成的符号。因此,在本例中,将出现的name-w-prefix
替换为name-w-prefix#
,您应该可以开始了
退一步,看看您的总体目标是什么,我认为您应该将name-w-prefix
定义移到语法引号之外,然后使用语法转义来调用它。否则,您将得到更多错误,因为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#))))))
请注意,我已根据上面所说的内容将~'[tag]
更改为[tag#]
,位于defn
正文中。谢谢您的解释!我不知道。。但我这样做了,现在它抱怨函数定义中的x
符号..请参见编辑。我想你对语法引号的内部和外部有点困惑。是的,看起来像!例如,我认为因为它都是关于AST的,所以我可以像~(expr)
一样从函数返回,它将替换调用者,就像在这里显式编写一样。但是看起来,~
的工作方式不同。。。谢谢你的~'
->#
建议!现在我已经修复了所有宏,它工作得很好!