1. ホーム
  2. lisp

[解決済み] Lispで'(またはquote)はいつ使うのか?

2022-08-10 04:56:56

質問

Lispの入門書の主要な部分を読んでも、特殊な演算子である (quote) (または同等の ' ) 関数がありますが、これは私が見た Lisp コードの至る所にありました。

これは何をするものなのでしょうか?

どのように解決するのですか?

短い答え デフォルトの評価ルールをバイパスして ではなく は式(symbolまたはs-exp)を評価し、タイプされたとおりにそれを関数に渡します。

長い回答です。デフォルトの評価ルール

通常の(後で説明します)関数が呼び出されると、それに渡されたすべての引数が評価されます。つまり、こう書けばいいのです。

(* (+ a 2)
   3)

を評価し、次に (+ a 2) を評価することによって a と2. の値は、記号 a の値は、現在の変数バインディングセットで検索され、置換されます。 例えば a は現在値 3 に束縛されているとします。

(let ((a 3))
  (* (+ a 2)
     3))

私たちは (+ 3 2) となり、+は3と2に対して発動し、5を生成します。 元の形式は次のようになります。 (* 5 3) であり、15となります。

説明する quote もう!

よしっ。上で見たように、関数への引数はすべて評価されるので、もしあなたが 記号 a というように、シンボルの値ではなく、そのシンボルを評価することはありません。 Lispのシンボルは値としても、ハッシュテーブルのキーなど他の言語では文字列を使用するようなマーカーとしても使用できます。

これは quote の出番です。 Python アプリケーションからリソースの割り当てをプロットしたいが、プロットは Lisp で行いたい場合を考えてみましょう。 Pythonアプリケーションにこのようなことをさせます。

print("'(")
while allocating:
    if random.random() > 0.5:
        print(f"(allocate {random.randint(0, 20)})")
    else:
        print(f"(free {random.randint(0, 20)})")
    ...
print(")")

このような出力が得られます(少し美化されています)。

'((allocate 3)
  (allocate 7)
  (free 14)
  (allocate 19)
  ...)

について言ったことを思い出してください。 quote ("tick") がデフォルトのルールを適用しない原因になっていると言ったのを覚えていますか?いいですね。そうでない場合はどうなるかというと allocatefree が検索されるのは困りものです。 私たちのLispでは、そうしたいと願っています。

(dolist (entry allocation-log)
  (case (first entry)
    (allocate (plot-allocation (second entry)))
    (free (plot-free (second entry)))))

上記のデータに対して、次のような一連の関数呼び出しが行われたはずです。

(plot-allocation 3)
(plot-allocation 7)
(plot-free 14)
(plot-allocation 19)

しかし list ?

さて、時々、あなたは する は引数を評価したい場合があります。 例えば、数値と文字列を操作して、その結果のリストを返すような関数があるとします。 試しにやってみましょう。

(defun mess-with (number string)
  '(value-of-number (1+ number) something-with-string (length string)))

Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER (1+ NUMBER) SOMETHING-WITH-STRING (LENGTH STRING))

おい!それは俺たちが望んでいることじゃない。 私たちが望んでいるのは を選択的に を評価し、他の引数はシンボルとして残すのです。2を試してみてください。

(defun mess-with (number string)
  (list 'value-of-number (1+ number) 'something-with-string (length string)))

Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER 21 SOMETHING-WITH-STRING 3)

だけでなく quote でも backquote

ずっといい! ちなみに、このパターンは (主に) マクロで非常によく見られるため、これを行うための特別な構文が存在します。バッククオートです。

(defun mess-with (number string)
  `(value-of-number ,(1+ number) something-with-string ,(length string)))

を使っているようなものです。 quote と同じですが、いくつかの引数の前にカンマを付けて明示的に評価するオプションがあります。 結果は list と同じですが、マクロからコードを生成する場合、返されるコードの小さな部分のみを評価したいことがよくあるので、バッククォートの方が適しています。 短いリストには list はより読みやすくなります。

を忘れていませんか? quote !

さて、この先はどうなるのでしょうか?そうですね quote は実際に何をしているのでしょうか?それは、単にその引数(複数可)を評価せずに返しているだけなのです。 冒頭で普通の関数について述べたことを思い出してください。 ある種の演算子や関数には ではなく で評価する必要があることがわかりました。 例えばIFのように、elseブランチが取られなかったら評価されたくないでしょう? いわゆる 特殊演算子 は、マクロと一緒になって、そのような働きをします。特殊演算子はまた、言語の公理、つまり最小限のルールの集合であり、それらを様々に組み合わせることによって、Lispの他の部分を実装することができるのです。

戻る quote が、しかし。

Lisp> (quote spiffy-symbol)
SPIFFY-SYMBOL

Lisp> 'spiffy-symbol ; ' is just a shorthand ("reader macro"), as shown above
SPIFFY-SYMBOL

(Steel-Bank Common Lisp上)と比較してください。

Lisp> spiffy-symbol
debugger invoked on a UNBOUND-VARIABLE in thread #<THREAD "initial thread" RUNNING   {A69F6A9}>:
  The variable SPIFFY-SYMBOL is unbound.

Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [ABORT] Exit debugger, returning to top level.

(SB-INT:SIMPLE-EVAL-IN-LEXENV SPIFFY-SYMBOL #<NULL-LEXENV>)
0] 

は存在しないので spiffy-symbol がないからです。

まとめ

quote , backquote (カンマ付き)、および list は、リストを作成するために使用するツールの一部で、単なる値のリストではなく、ご覧のように軽量なものとして使用することができます (リスト内で struct を定義する必要はありません) データ構造として使用できます!

もっと学びたいのであれば、Peter Seibelの著書である 実践的Common Lisp をお勧めします。これはLispを学ぶための実用的なアプローチで、もしあなたが既にプログラミングに夢中になっているのであれば。Lispの旅の途中では、最終的にはパッケージも使うようになります。Ron Garret の The Idiot's Guide to Common Lisp Packages (邦題: Lispパッケージ入門) を読むと、それらの説明がよくわかります。

ハッピーハッキング!