2013-02-27 39 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