4

dispatcher私は、3つの関連付けられた関数get-dispatcherで名前付きset-dispatcherを作成し、ディスパッチャーを操作するマクロを作成しましたcall-dispatcher(ディスパッチ関数を取得し、追加するか、呼び出します)。それはすべてうまくいきます!ただし、関連する関数名の作成を自動化したいので、マクロのこれらすべての内部let構造を単純な構築関数を定義する に入れています。以下のコードでは、get-関数の名前のみがそのオートメーションで構築されていることに注意してください。set-and onesの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!")
    ))

ただし、問題があります。ステートメント バインドname-w-prefix内でエラーが発生します。letどうすれば修正できますか?

(また、私は初心者であり、Clojureで書いたのはほとんど最初のことなので、改善に関するアドバイスは大歓迎です)

4

1 に答える 1

9

マクロ内のすべてのシンボルは、現在の名前空間で解決され、var に評価されることが期待されます。シンボルを引用することもできますが、name-w-prefixマクロの展開中にマクロに渡されたシンボルと衝突する危険があります。そのため、Clojure は、シンボルを生成するために構文引用符付きの形式で使用するための特別な構文を提供します。#シンボルの末尾に a を追加するだけで、Clojure はそれを引用符付きの自動生成シンボルとして扱います。したがって、この場合は、出現箇所をname-w-prefixwithに置き換えれば、準備完了name-w-prefix#です。

一歩下がって、全体的な目標が何であるかを見て、name-w-prefix定義を構文引用符のに移動してから、syntax-escape を使用して呼び出す必要があると思います。そうしないdefnと、シンボルが必要なため、さらに多くのエラーが発生するため、マクロを展開するdefnと、2 番目の項目としてシンボルを持つフォームを生成する必要があります。次のようなもの:

(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#))))))

上記で話していたことに従って、in the body に変更~'[tag]したことに注意してください。[tag#]defn

于 2013-02-27T21:06:29.020 に答える