2012-06-11 9 views
5

私は、コンパイルに使用されているミドルウェアに似たミドルウェアを構築するマクロを作成しようとしています。関数から高次関数を構築するClojureマクロ

私が呼び出すことができるようにしたい:

(def-middleware plus-two [x] 
    (+ 2 x)) 

をし、その結果は次のようになります:私はこれまでのところは、オンラインのガイドを読んでから持っているが、それは出て働いていない

(defn plus-two [f] 
(fn [x] 
    (f (+ 2 x))) 

私のために:

(defmacro def-middleware [fn-name args & body] 
    '(defn ~fn-name [f] 
    (fn ~args 
     (f [email protected])))) 

より良いマクロ作成ガイドへの助けや偉大な、ありがとう。

user=> (clojure.pprint/pprint (macroexpand-1 '(def-middleware plus-two [x] (+ 2 x)))) 
(defn 
~fn-name 
[f] 
$ 
(fn ~args$ (f (clojure.core/unquote-splicing body)))) 

ない正確に、我々は後にしているもの:

+0

どのようにあなたのためにうまくいかないのですか? –

+0

CompilerException java.lang.RuntimeException:defへの最初の引数は、コンパイルするシンボルでなければなりません。(NO_SOURCE_PATH:33) – jdoig

+0

一重引用符ではなくバックティックを使用します – Alex

答えて

8

はのはmacroexpand-1が私たちを与えるか見てみましょう!まず最初に、マクロ内のものを引用符で囲まないようにするには、 "'"ではなく "` "(quasi quote/syntax-quote演算子)を使用する必要があります。また、それらのドル記号であなたが何をしているのか分からないが、かもしれないあなたは衛生のためにgensymを使用するための便利なショートカットのために行くと思っていることになります。しかし、それを使用する各識別子の直後(つまり[f#]ではなく、[f]$)にそれを必要とし、識別子の各出現時にそれを必要とします。そしてあなたはではありませんargsとそれが必要です。一緒にこのすべてを置く:

user=> (defmacro def-middleware [fn-name args & body] `(defn ~fn-name [f#] (fn ~args (f# [email protected])))) 
#'user/def-middleware 
user=> (clojure.pprint/pprint (macroexpand-1 '(def-middleware plus-two [x] (+ 2 x)))) 
(clojure.core/defn 
plus-two 
[f__594__auto__] 
(clojure.core/fn [x] (f__594__auto__ (+ 2 x)))) 
nil 
user=> 
+0

申し訳ありませんが$ Vimからコピー&ペーストするフォームです。そして、あなたはそれが欠けていた#だったそうです:)ありがとう。 – jdoig

3

をおそらくこれは単なるマクロ運動ですが、ミドルウェアの機能を定義する具体的な例としては良くありません - あなたは、ミドルウェアのコンセプトはあなたを与えることを多くの柔軟性を失います。たとえば、(+ 2 (f x))の代わりに(f (+ 2 x))と評価するのはなぜですか?両方ともこの関数をラップするのに賢明な方法であり、構文では後者を記述する方法がありません。実際に関数を返す関数を定義することは、柔軟性があり、シンプルで簡単です。このマクロはテーブルにはほとんど持ち込まれません。

+0

ありがとうございましたamalloy;私はマクロを学び、何かを包み込むこの大きなダムのビルディングとは対照的に、より具体的なミドルウェアのようなビルディング関数を構築するための足掛かりとして使用しています...あなたが正しいように、短絡することはできません、など、それは物事を包む方法などについては説明できません。 – jdoig