マクロ内のreifyの一部としてのフォームを動的にする

さて、これを真似しようとしましょう。私の最終的な目的は、ユーザーにAPIとしてマクロを提供することです。

(defscript [a b]
  (println a))

結果は次のような Script プロトコルのインスタンスでなければなりません:

(defprotocol Script
  (run [this model]))

defscript の最初の引数は、 model の対応するキーにバインドする必要のあるシンボルのリストです。

(.run (defscript [a b] (println a)) {:a 1}) ;; yields 1

マクロ拡張時に単なるシンボルなので、 model パラメータを使用しようとすると壁を突き抜けているので、効果的にそのような効果を生み出すことができるコードを思いつくことはできません:

(defmacro invoke-
  [params model body]
  (let [p (flatten (map (fn [x] [x (model (keyword x))]) params))]
    `(let [[email protected]]
       ~body)))

(defmacro defscript
  [params & body]
  `(reify Script
    (run [~'this ~'model]
      (invoke- ~params ~'model [email protected]))))

invoke- works fine if called directly:

(invoke- [a] {:a 1} (println a)) ;; prints 1

model として正しく展開できないため、 defscript 内で使用するとうまく動作しません。

(.run (defscript [a] (println a)) {:a 1}) ;; prints nil

私はこの点を過ぎて一緒に糊付けすることができますか?

2
あなたが記述していることは、 clojure.template で提供されている機能とぼんやりとしているようです。
追加された 著者 Alex Taggart,

1 答え

基本的に、引数ベクトルは構造化バインディングのためのショートカットです:

(defscript [a b] body)  -> (reify Script (run [this {:keys [a b]}] body))

そうすれば、モデルは実行時に破棄されるはずです。

4
追加された
本当に素敵です!
追加された 著者 kotarak,
純粋なawesomeness、ありがとう!
追加された 著者 skuro,