2013-02-27 47 views
2

我创建了创建一个名为dispatcher与3同伙功能get-dispatcherset-dispatchercall-dispatcher与调度员的工作(他们得到一个调度功能,添加一个或拨打一个宏)。这一切都很好!但是,现在我想自动创建相关的函数名称,因此我将所有这些宏的内部元素放入一个定义了这个简单构造函数的let中。请注意,在下面的代码中,只有get-函数的名称由该自动化构造而成。 set-call-这些名字的创造仍然有那种手工的气味。Clojure的 - 在宏一个让行不通

(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写的第一件事)

回答

5

在宏的所有符号在当前名字空间被解析和预期,以评估变种您可以引用name-w-prefix符号,但这会在宏扩展期间与传递给宏的符号发生碰撞。因此,Clojure提供了一种特殊的语法,用于语法引用的表单中用于生成符号 - 只需在符号的末尾附加#,Clojure会将其视为带引号的自动生成符号。因此,在这种情况下,请将name-w-prefixname-w-prefix#替换,您应该很好。

退一步看看您的总体目标是什么,我认为您应该将name-w-prefix定义定义为以外的语法引号,然后使用syntax-escape来调用它。否则,由于defn需要一个符号,所以会出现更多错误,因此一旦展开宏,必须生成一个defn表单,其中第二个项目具有符号。我已经改变了~'[tag][tag#]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#)))))) 

注:沿着线的东西。

+0

感谢您的解释!不知道..但是我做了它,现在它抱怨函数定义中的'x'符号。 – noncom 2013-02-27 21:15:40

+0

请参阅编辑。我认为你对语法引用内部和外部的内容有点困惑。 – Alex 2013-02-27 21:37:45

+0

是啊,看起来像!例如,我认为,因为它完全关于AST,所以我可以像函数中的'〜(expr)'那样返回,并且它将替换调用者,就像在这里显式写入一样。但看起来'〜'的工作方式不同......感谢'〜'''>'#'建议!现在我已经修复了所有宏,并且它工作正常! – noncom 2013-02-27 22:37:44