2017-05-13 4 views
0

Mapped calls to clojurescript macroClojure `defn`関数をマクロなしで自動的に作成するには?もともとは、次の質問が動機


は、あなたが(つまり手書きそれらすべてをせずに)自動的に多くの類似の機能を作成するとします。我々はいくつかの既存の機能を持っていると我々はいくつかの並べ替えのコールバック用のハンドラでそれらをラップしたいと:

結果と
(defn do-foo [] (println "I foo'ed")) 
(defn do-bar [] (println "I bar'ed")) 
(defn do-baz [] (println "I baz'ed")) 

(defn manual-on-foo [] (do-foo)) 
(defn manual-on-bar [] (do-bar)) 
(defn manual-on-baz [] (do-baz)) 

(println "Calling manual-on-* functions") 
(manual-on-foo) 
(manual-on-bar) 
(manual-on-baz) 

Calling manual-on-* functions 
I foo'ed 
I bar'ed 
I baz'ed 

私たちは、ラッパー関数を生成する自動の代わりに、手動で。

この機能を作成するにはマクロが必要だと思うかもしれませんが、それが1つの解決策です。しかし、マクロの弱点は、引数として他の関数、例えばmapに渡すことができないことです。したがって、我々は次のようなマクロを書くことができます:

(generate-fn :foo) ;=> creates `on-foo` w/o hand-writing it 

が、次は失敗します:

(map generate-fn [:foo :bar :baz]) 

どのように我々は、これらの機能の生成を自動化することができますか?

答えて

2

概要

あなたはマクロでmapを使用することはできませんが、この機能を実行するために2番目のマクロを書くことができます。これは、順番に、Clojure for the Brave and Trueおよび他の場所に記載されているように、「Macros All Way Way」というフレーズの起源である第3のマクロなどを書くことを必要とすることがある。

類似の質問was answered hereをClojureのintern関数を使用して実行します。

  • var-get
  • を使用して、グローバルvarの値にアクセスするには defまたは defn
  • とのようなグローバルVARを作成するには:ここで我々は2つの異なる方法でinternを使用するので、私たちの問題は、その質問よりも少し異なっていますinternを使用して

機能ソリューション

は、私たちは、自動的にon-* functiを生成するには、次のコードを記述することができます

*** generating functions *** 
Created on-foo 
Created on-bar 
Created on-baz 

Calling automatically generated on-* functions 
I foo'ed 
I bar'ed 
I baz'ed 

だから我々は、我々は機能on-fooを作成していることがわかり、on-bar & on-baz今度は、グローバルdo-foodo-bar、& do-baz関数を呼び出し、:結果と

(defn generate-onstar-f 
    [event-kw] 
    (let [ 
    event-str (name event-kw) 
    do-fn-sym (symbol (str "do-" event-str)) 
    on-fn-sym (symbol (str "on-" event-str)) 
    new-fn (fn on-fn-sym [] 
       (let [the-var (intern 'tst.clj.core do-fn-sym) ; get the var the symbol 'do-fn-sym' points to 
         the-fn (var-get the-var) ] ; get the fn the var is pointing to 
        (the-fn))) ] 
    (intern 'tst.clj.core on-fn-sym new-fn) ; create a var 'on-fn-sym' pointing to 'new-fn' 
    (println "Created" on-fn-sym))) 

(println \newline "*** generating functions ***") 
(mapv generate-onstar-f [:foo :bar :baz]) ; creates and interns a functions: my-foo, my-bar, my-baz 

(println \newline "Calling automatically generated on-* functions") 
(on-foo) 
(on-bar) 
(on-baz) 

:アドオンマクロを使用せず。マクロを使用する必要はありませんでした。

Clojureでは、varは、on-fooのようなシンボルと(この例では関数である)値の間の見えない「中級者」のものです。詳細については、ポスト関連参照してください。前述のように

When to use a Var instead of a function?


マクロソリューション

を、一つは別のマクロを呼び出すために、マクロを使用することができ、「マクロができ、問題をサイドステップmapのような高次関数(HOF)で使用することができます。ここでは、我々は我々がgenerate-onstar-fで使用することはできませんmap HOF置き換えるために、新しいマクロrun-macroを定義します。

結果と
(defmacro generate-onstar-m 
    [event-kw] 
    (let [event-str (name event-kw) 
     do-fn-sym (symbol (str "do-" event-str)) 
     on-fn-sym (symbol (str "on-" event-str "-m"))] 
    (println "Creating" on-fn-sym) 
    `(defn ~on-fn-sym [] 
     (~do-fn-sym)))) 

(println \newline "Using Macro") 
(generate-onstar-m :foo) 
(on-foo-m) 

(defmacro run-macro 
    "Run the specified macro once for each arg" 
    [root-macro args] 
    `(do 
    [email protected](forv [item args] 
     `(~root-macro ~item)))) 

(println \newline "Generating on-*-m functions using `run-macro`") 
(run-macro generate-onstar-m [:foo :bar :baz]) 
(on-foo-m) 
(on-bar-m) 
(on-baz-m) 

Using Macro 
Creating on-foo-m 
I foo'ed 

Generating on-*-m functions using `run-macro` 
Creating on-foo-m 
Creating on-bar-m 
Creating on-baz-m 
I foo'ed 
I bar'ed 
I baz'ed 
関連する問題