5

Clojureでは、値のリストを引用符でつなぎ合わせてコードを生成できます。

(def extra-values [1 2 3 4])

`(+ 100 200 ~@extra-values)
=> (clojure.core/+ 100 200 1 2 3 4)

同じアプローチが引用符で囲まれていないコンテキストで機能することは論理的に思われます。

(def extra-values [1 2 3 4])

(+ 1000 ~@extra-values)
=> [an error, but one could argue that the answer should be 1010??]

これが機能しない深い技術的/哲学的理由はありますか?

4

2 に答える 2

13

単純な理由の1つは、

`(+ 100 200 ~@extra-values) 

定義が不十分です:それはに拡張されますか

(+ 100 200 1 2 3 4)

またはに

(+ 100 200 ~@extra-values)

~@構成がそのコンテキストで合法である場合、両方とも有効な解釈です。

また、マクロシステムで深刻な問題を引き起こします。検討

(defmacro foo [x & args]
  `(list ~x ~(count args)))

(let [data '(1 2 3)]
  (foo "three" ~@data))

foo渡されている引数をどのように知ることができますか?コンパイル時にそれを拡張することは確かにできないため、引用符で囲まれていないスプライシングは、引用符で囲まれていない一部のコンテキストでのみ有効になります。

そして全体として、コアコンセプトの理解不足に対応するために言語を混乱させているだけです-引用符を外して複雑な引数リストを作成したい場合はapply、次のようなもので簡単に使用できます

(apply + `(100 ~@extra-values 200))
于 2012-02-07T04:51:33.627 に答える
2

、、のポイントはsyntax-quote、開発unquoteunquote-splicingがマクロを作成するのを支援することです。

たとえば、なしsyntax-quoteで、unquoteあなたは書く必要があります

user=> (list :a extra-values)
(:a [1 2 3 4])

それ以外の:

user=> `(:a ~extra-values)
(:a [1 2 3 4])

前者の場合、読者(人間の読者-担当者ではない)が結果のフォームがどのように見えるかを理解するのは困難ですが、後者の場合は結果のフォームの「形状」を維持します。

では、代わりに、要素としてのコンテンツを結果のフォームvector [1 2 3 4]にスプライスしたい場合はどうでしょうか。次のように書くことができるようにするextra-values必要があります。unquote-splicing

user=> `(+ 100 200 ~@extra-values)
(clojure.core/+ 100 200 1 2 3 4)

それ以外の:

user=> (concat `(+ 100 200) extra-values)
(clojure.core/+ 100 200 1 2 3 4)

このunquote-splicingバージョンでも、コードが評価されるときに、コードが結果のフォームの「形状」に似ていることが許可されますが、後者のバージョンでは、「形状」がとのノイズで失われapplyますlist

これらの例はどちらも非常に単純ですがsyntax-quote、より複雑なマクロを作成する場合、友人は本当に自分自身になります。

なぜあなたが書くことができないのかというあなたの質問に戻ります(+ 1000 ~@extra-values)か?すでにその機能がありますapply(さらにいくつかの制限があります):

user=> (apply + 1000 extra-values)
1010
于 2012-02-09T15:29:04.827 に答える