Haskell (または Nemerle) などの一部の言語にはquasiquotationsがあります。「準」は何を意味するのか、「準」の部分のない「引用」もあるのだろうか。
5 に答える
この概念は Lisp 言語から来ていると思います。
Lisp で書かれたプログラムは、次のように、リストのリストのリストなどの一連のリストで構成されます。
(defn f [x y] (+ x y))
このような統一性により、そのようなコードをデータとして表現および操作することが可能であり、上記の文字列はリテラル リストとして解釈されます。これは Lips の非常に便利な機能であり、独特の機能の 1 つです。便宜上、Lisp 言語では意味のあるシーケンスを「引用」して、それらを定義と式からリストに変換することができます。次のようになります。
'(defn f [x y] (+ x y))
この場合、これはリテラル リストであり、Haskell やその他のメソッドの類似物を使用して直接分解できhead
ますtail
。したがって、「引用」は「リストからリテラル値を作成する」ことを意味します。
head
ただし、 - や - のtail
ような関数でリストを直接操作するのは便利ではありません。複雑なマクロやマクロ生成マクロを書き始めると、それが顕著になります。ここで「quasiquotation」、文字通り「ほぼ引用」が登場します。通常、quasiquotation は単純な引用のように見えます (ただし、別の引用記号が付いています)。
`(defn f [x y] (+ x y))
しかし、それははるかに強力なものです。準引用符で囲まれたリストでは、任意の要素を外側のスコープからの実際の値に置き換えることができ、基本的にパターンのようなものを取得できます。例:
(let [z 10] `(defn f [x y] (+ x y ~z)))
ここでは、値10
をz
変数にバインドしてから、それを準引用符内に代入しています。この式は
'(defn f [x y] (+ x y 10))
これは簡単な例です。Lisp 言語では、準引用符を使用して他の多くの便利なことを行うことができます。
この概念は、構文ツリーによる操作をサポートする他の言語に移行しました。たとえば、ここでの Haskell 機能は Template Haskell であり、準引用符を完全にサポートしています。つまり、テンプレートを作成し、外側のスコープから値を入力します。複雑な構文を持つ言語 (Haskell など) では、準引用符と単純引用符が、構文ツリーを操作するためのほぼ唯一の適切な方法になります。
UPD: うーん、Haskell では、単純な置換よりも洗練された機能のようです。Haskell の Quasiquote は、ユーザーが定義できる式の任意の変換器および評価器のように見えます。
これらの概念は、Lisp 言語とその変種に存在します。
これらの言語では、インタプリタが list を見るたびに(a b c ... z)
、それを評価a
し、他の要素に適用しますb ... z
。
リストを評価しない (したがってリストとして解釈する) 場合は、それを引用符で囲む必要があります。たとえば、はandに適用される'(a b c)
のではなく、3 つの要素を持つリストとして評価されます。評価を停止すると、引用が表示されます。a
b
c
リストの一部の内部で評価を再開できることを除いて、quasiquotation は quote のように動作するようになりました。後方アポストロフィ ` で準引用符を付け、特定の部分式をカンマ演算子で引用符で囲むことを許可します (少なくとも、Scheme では、他の Lisp バリアントについては知りません)。例えば
`(a ,(b c))
a
は、 と の評価結果の2 つの要素を持つリストに評価され(b c)
ます。
これは、引用符を外して穴を埋めるテンプレートを作成する場合に特に便利です。例(そこから取得):
(define (create-shipping-employee-association name)
`((name ,name)
(employee-id-no ,(get-next-employee-id!))
(department shipping)
(hire-date ,(get-day) ,(get-month) ,(get-year))))
Nemerle では、準引用は ( http://nemerle.org/metaprogramming.pdf ):
"
メタ言語は、このような操作をプログラミングするための言語です。通常、オブジェクト言語のさまざまな構造を記述するための独自の構文があります。
たとえば、私たちのシステムでは:
<[ 1 + f (2 * x) ]>
式の構文木を示します。
1 + f (2 * x)
この考え方は準引用と呼ばれます。
接頭辞quasiは、メタ言語表現の値を引用されたコンテキストに挿入する可能性に由来します。
がそのような式である場合g(y)
、次のように書くことができます。
<[ 1 + $(g(y)) ]>
これは構文木を記述し、その 2 番目の部分は次の評価の結果に置き換えられます。g(y)
"
引用符は単なる文字列リテラルです。 準引用符は、コンパイルされたコードではなく、何らかの意味で入力を表すという意味で「引用符で囲まれている」。それらは、コンパイル プロセス内から操作しやすい形式 (テキストを操作するよりもいくらか安全なさまざまな方法で移植できる抽象構文ツリー) でそれを表現するだけです。
準とは基本的に、引用符の中にドル記号を入れて、引用符で囲まれていないコードに再び切り替えることができることを意味します。
<[ WriteLine( $(ReadLine()) ) ]>
これは、コンパイル時に入力された文字列を実行時に出力します (実際には、ReadLine にはコンソール入力が必要なため、たとえば Visual Studio では機能しないと思いますが、ファイルやネットワークなどから読み取ることができます)。