'
(別名quote
)を使用してリストを作成します。これを次のように常に使用しています:
> (car '(1 2 3))
1
しかし、期待どおりに機能するとは限りません。たとえば、次のように関数のリストを作成しようとしましたが、機能しませんでした。
> (define math-fns '(+ - * /))
> (map (lambda (fn) (fn 1)) math-fns)
application: not a procedure;
expected a procedure that can be applied to arguments
given: '+
list
を使用すると、次のように機能します。
> (define math-fns (list + - * /))
> (map (lambda (fn) (fn 1)) math-fns)
'(1 -1 1 1)
どうして? '
は便利な省略表現でしたが、なぜ動作が異なるのですか?
list
を使用してください。経験則:引数を評価する場合は常にlist
を使用します。 quote
は引数に「分散」するため、'(+ 1 2)
は_(list '+ '1 '2)
_のようになります。関数ではなく、シンボルがリストに表示されます。
list
とquote
の詳細SchemeとRacketでは、quote
とlist
はまったく異なるものですが、どちらもリストの作成に使用できるため、混乱が一般的で理解可能です。それらの間には非常に重要な違いがあります:list
は単純な古いfunctionですが、quote
(特別な_'
_構文なしでも)は- 特別な形式。つまり、list
はプレーンスキームで実装できますが、quote
は実装できません。
list
関数list
関数は実際には2つのうちはるかに単純なので、それから始めましょう。これは、任意の数の引数を取る関数であり、引数をリストに収集します。
_> (list 1 2 3)
(1 2 3)
_
上記の例は、結果がquote
able s式として出力され、trueである場合、混乱を招く可能性があります。この場合、2つの構文は同等です。しかし、もう少し複雑になると、それが異なることがわかります。
_> (list 1 (+ 1 1) (+ 1 1 1))
(1 2 3)
> '(1 (+ 1 1) (+ 1 1 1))
(1 (+ 1 1) (+ 1 1 1))
_
quote
の例では何が起こっていますか?それについてはすぐに説明しますが、最初にlist
を見てください。これは単なる通常の関数であるため、標準のScheme評価セマンティクスに従います。引数のそれぞれを評価しますbefore関数に渡されます。つまり、_(+ 1 1)
_のような式は、リストに収集される前に_2
_に削減されます。
この動作は、変数をリスト関数に提供するときにも表示されます。
_> (define x 42)
> (list x)
(42)
> '(x)
(x)
_
list
では、x
がlist
に渡される前に評価されます。 quote
を使用すると、状況はさらに複雑になります。
最後に、list
は単なる関数なので、高階の方法を含め、他の関数と同じように使用できます。たとえば、map
関数に渡すことができ、適切に機能します。
_> (map list '(1 2 3) '(4 5 6))
((1 4) (2 5) (3 6))
_
quote
フォームlist
とは異なり、引用はLispの特別な部分です。 quote
フォームは、特別なリーダー略語__'
_を取得するという点で特別ですが、それがなくてもalso特別です。 list
とは異なり、quote
はnot関数であるため、関数のように動作する必要はありません。独自のルールがあります。
SchemeとRacketが派生しているLISPでは、すべてのコードは実際には通常のデータ構造で構成されています。たとえば、次の式について考えてみます。
_(+ 1 2)
_
その式は実際にはa listであり、3つの要素があります。
+
_シンボル1
_2
_これらの値はすべて、プログラマーが作成できる通常の値です。 _1
_の値は、それ自体が評価されるため、簡単に作成できます。つまり、_1
_と入力するだけです。しかし、シンボルとリストはより困難です。デフォルトでは、ソースコード内のシンボルは変数ルックアップを実行します。つまり、シンボルは自己評価ではありません。
_> 1
1
> a
a: undefined
cannot reference undefined identifier
_
しかし、結局のところ、シンボルは基本的に単なる文字列であり、実際にはそれらの間で変換できます。
_> (string->symbol "a")
a
_
デフォルトでは、ソースコードのリスト関数を呼び出す! _(+ 1 2)
_を実行すると、リストの最初の要素である_+
_シンボルが参照されるため、リストはシンボル以上の機能を備えています。 、それに関連付けられている関数を検索し、リスト内の残りの要素とともに呼び出します。
ただし、この「特別な」動作を無効にしたい場合もあります。リストを取得するか、評価せずにシンボルを取得することができます。これを行うには、quote
を使用できます。
これらすべてを念頭に置いて、quote
が何をするかは非常に明白です。ラップする式の特別な評価動作を「オフにする」だけです。たとえば、シンボルをquote
ingすることを検討してください:
_> (quote a)
a
_
同様に、リストをquote
ingすることを検討してください:
_> (quote (a b c))
(a b c)
_
quote
を何に指定しても、常にalways吐き出されます。それ以上でもそれ以下でもありません。つまり、リストを指定した場合、部分式は評価されません。それらが評価されることを期待しないでください!何らかの評価が必要な場合は、list
を使用してください。
さて、あなたは尋ねるかもしれません:あなたがシンボルやリスト以外のものをquote
した場合どうなりますか?ええと、答えは...何もありません!あなたはそれを取り戻すだけです。
_> (quote 1)
1
> (quote "abcd")
"abcd"
_
quote
は、与えたものを正確に吐き出すだけなので、これは理にかなっています。これが、数値や文字列のような「リテラル」がLISP用語で「自己引用」と呼ばれることがある理由です。
もう1つ:quote
を含む式をquote
するとどうなりますか?つまり、「double quote
」を実行するとどうなるでしょうか。
_> (quote (quote 3))
'3
_
そこで何が起こった?まあ、_'
_は実際にはquote
の直接の省略形であることを忘れないでください。そのため、特別なことは何も起こりませんでした。実際、Schemeに印刷時に略語を無効にする方法がある場合、次のようになります。
_> (quote (quote 3))
(quote 3)
_
quote
が特別であることにだまされないでください。_(quote (+ 1))
_と同様に、ここでの結果は単純な古いリストです。実際、リストから最初の要素を取得できます。それがどうなるかを推測できますか?
_> (car (quote (quote 3)))
quote
_
_3
_を推測した場合、それは間違いです。 quote
はすべての評価を無効にすることに注意してください。quote
記号を含む式は、単なるプレーンリストです。 REPLでこれに慣れるまでこれで遊んでください。
_> (quote (quote (quote 3)))
''3
(quote (1 2 (quote 3)))
(1 2 '3)
_
見積もりは信じられないほど単純ですが、従来の評価モデルに対する私たちの理解に反する傾向があるため、非常に複雑になる可能性があります。実際、それは混乱しています理由それがどれほど単純であるかということです:特別なケースはなく、ルールもありません。これは、指定したとおりに正確に返すだけです(したがって、「引用」という名前です)。
それで、見積りが評価を完全に無効にする場合、それは何に役立ちますか?まあ、文字列、記号、または数値のリストを作成することは別として、すべてが事前にわかっていることはあまりありません。幸い、quasiquotationの概念は、引用符から抜け出し、通常の評価に戻る方法を提供します。
基本は非常に単純です。quote
を使用する代わりに、quasiquote
を使用します。通常、これはquote
とまったく同じように機能します。
_> (quasiquote 3)
3
> (quasiquote x)
x
> (quasiquote ((a b) (c d)))
((a b) (c d))
_
quasiquote
を特別にするのは、特別な記号unquote
を認識することです。 unquote
がリストのどこにある場合でも、そこに含まれる任意の式に置き換えられます。
_> (quasiquote (1 2 (+ 1 2)))
(1 2 (+ 1 2))
> (quasiquote (1 2 (unquote (+ 1 2))))
(1 2 3)
_
これにより、quasiquote
を使用して、unquote
で埋められる「穴」を持つソートのテンプレートを作成できます。つまり、引用符で囲まれたリスト内に変数の値を実際に含めることが可能です。
_> (define x 42)
> (quasiquote (x is: (unquote x)))
(x is: 42)
_
もちろん、quasiquote
とunquote
の使用はかなり冗長であるため、_'
_のように、それぞれに独自の省略形があります。具体的には、quasiquote
は_`
_(バックティック)であり、unquote
は_,
_(カンマ)です。これらの略語を使用すると、上記の例ははるかに口当たりが良くなります。
_> `(x is: ,x)
(x is: 42)
_
最後のポイントの1つは、quasiquoteが実際にcanかなり毛深いマクロを使用してラケットに実装されているということです。 list
、cons
、そしてもちろんquote
の使用法に拡張されます。
list
およびquote
の実装list
の実装は、「残余引数」構文がどのように機能するかにより、非常に簡単です。これで十分です。
_(define (list . args)
args)
_
それでおしまい!
対照的に、quote
ははるかに困難です。実際、不可能です。評価を無効にするという考えはマクロとよく似ているので、それは完全に実現可能に思えます。しかし、素朴な試みは問題を明らかにします:
_(define fake-quote
(syntax-rules ()
((_ arg) arg)))
_
arg
を取り、それを吐き出すだけですが、これは機能しません。何故なの?さて、私たちのマクロの結果が評価されるので、すべてが無意味です。次のように、_(list ...)
_に展開し、要素を再帰的に引用することで、quote
のようなものに展開できる場合があります。
_(define impostor-quote
(syntax-rules ()
((_ (a . b)) (cons (impostor-quote a) (impostor-quote b)))
((_ (e ...)) (list (impostor-quote e) ...))
((_ x) x)))
_
残念ながら、手続き型マクロがないと、quote
がないとシンボルを処理できません。 _syntax-case
_を使用して近づけることはできますが、それでもquote
の動作をエミュレートするだけで、複製はしません。
この回答の例をラケットで試すと、期待どおりに印刷されない場合があります。多くの場合、次の例のように、先頭に_'
_が付いて印刷されることがあります。
_> (list 1 2 3)
'(1 2 3)
_
これは、ラケットがデフォルトで、可能な場合は結果を式として出力するためです。つまり、結果をREPLに入力して同じ値を返すことができるはずです。私は個人的にこの動作を見つけましたニースですが、引用を理解しようとすると混乱する可能性があります。オフにする場合は、_(print-as-expression #f)
_を呼び出すか、DrRacket言語メニューで印刷スタイルを「書き込み」に変更します。