私は Clojure マクロについて学んでおり、コード例にはコンストラクト'~symbol
orが含まれていることがあり~'symbol
ます。(quote
フォームが評価されないようにすること、および'
バッククォートがさらに名前空間修飾を追加すること、および ~ によって引用されたフォームが評価されることを知っています。私の質問は: 評価を停止してから開始することがなぜ有用なのですか? ~'symbol
とも'~symbol
違うと思いますが、どうしてですか?
2 に答える
~'symbol
非修飾シンボルを生成するために使用されます。Clojure のマクロはデフォルトで名前空間をキャプチャするため、マクロ内のシンボルは通常は に解決され(your-namespace/symbol)
ます。unquote-quote イディオムは(symbol)
、引用されたシンボルに評価されることにより、単純で修飾されていないシンボル名になります。Clojureの喜び より:
(defmacro awhen [expr & body]
`(let [~'it ~expr] ; refer to the expression as "it" inside the body
(when ~'it
(do ~@body))))
(awhen [:a :b :c] (second it)) ; :b
'~symbol
マクロなどに名前を挿入するために使用される可能性があります。ここでsymbol
は、値にバインドされます - let [symbol 'my-symbol]
。この値は、マクロが を評価して生成するコードに挿入されますsymbol
。
(defmacro def-symbol-print [sym]
`(defn ~(symbol (str "print-" sym)) []
(println '~sym))) ; print the symbol name passed to the macro
(def-symbol-print foo)
(print-foo) ; foo
~
関数のリーダーマクロですunquote
。引用符で囲まれたリスト内では、リテラルシンボルとして使用されるのではなく、シンボルが評価されます。
user> (def unquoted 4)
user>`(this is an ~unquoted list)
(user/this user/is user/an 4 clojure.core/list)
user>
引用符で囲まれていない記号を除くすべてが、引用符で囲まれていない記号が値4に解決された記号と同じように使用されました。これは、マクロの記述で最もよく使用されます。replは、結果のリストを出力するときに、名前の前に名前空間(ユーザー)も出力します。
多くのマクロは、基本的に、関数では実行できないものにわずかなバリエーションを加えるように設計された単なるテンプレートです。この不自然な例では、テンプレートマクロはdefへの呼び出しを生成することによって関数を定義します。引用符を外した構文引用符を使用すると、これがはるかに読みやすくなります。
user> (defmacro def-map-reducer [name mapper reducer]
`(defn ~name [& args#]
(reduce ~reducer (map ~mapper args#))))
#'user/def-map-reducer
user> (def-map-reducer add-incs inc +)
#'user/add-incs
user> (add-incs 1 2 3 4 5)
20
に比べ:
user> (defmacro def-map-reducer [name mapper reducer]
(let [args-name (gensym)]
(list `defn name [`& args-name]
(list `reduce reducer (list `map mapper args-name)))))
#'user/def-map-reducer
user> (def-map-reducer add-decs dec +)
#'user/add-decs
user> (add-decs 1 2 3 4 5)
10
user>
2番目の例では、構文引用符を使用していないため、auto-gensyms機能も使用していません。