Lispへの入力はどんな種類があるのか

Lispへの入力、つまり、REPループへの入力にはどんな種類があるのか、またそれが評価(eval)されるとどうなるのか、ざっくり説明させていただきます。

・Self evaluating objects (数字、文字列など) => そのまま
KISS>1

1  ;; self evaluating object つまり評価(eval)されても
   ;; 自分自身のまま

KISS>
KISS>3.2

0.32e1  ;; 3.2 = 0.32e1 数値としては同じ
        ;; REPループにおけるprint関数がどう
        ;; 表示するかの問題

KISS>
KISS>"been there, done that"

"been there, done that"  ;; 文字列も評価(eval)されても
                         ;; 同じです

KISS>
・シンボル => 変数や定数の参照
KISS>*pi*            ;; "*pi*"という名前のシンボル

0.3141592653589793e1 ;; 定数*pi*には円周率πの値が
                     ;; 設定されている

KISS>

ここで、*pi* というのが”*pi*”という名前のシンボルを表していおり、シンボルを評価(eval)すると、そのシンボルと結び付けられているLisp Objectを返すことになっています。(Cなどのプログラミング言語の定数や変数に相当)。

Lispでは、変数、関数、クラスなど各種Lisp Objectの名前を表すのにシンボルを使います。シンボルは処理系の実装でオブジェクトとして実体をもつものとして定義されることが多いのですが、その説明は別の機会に譲ります。

・リスト => 各種処理
KISS>(+ 1 2 3)  ;; リストの第一要素(ここでは+)によって
                ;; 色々起こる

6 ;; 1 + 2 + 3 = 6 ここでは+は引数をすべて足し算している

KISS>
KISS>(defun hello-world () "hello world!")  
     ;; hello-world関数を定義

hello-world ;; 関数定義が完了すると関数名のシンボルが返される

KISS>(hello-world) ;; 関数を呼び出してみる

"hello world!"

KISS>
KISS>(quote love) ;; quote はスペシャルオペレータと
                  ;; 呼ばれるもので関数とは引数の扱
                  ;; いが異なる

love              ;; quoteは1つのLisp Objectを受け取り、
                  ;; それをそのまま返す
                  ;; ここではシンボルlove。

KISS>'love        ;; quoteはよく使うので省略記法が
                  ;; 用意されている

love           ;; 'love ≡ (quote love)

KISS>love         ;; じゃ、quoteしないとどうなるか…

KISS| Unbound variable love

                  ;; 変数loveに値を設定していないのでエラー
KISS>

LispのREPループとは何なのか

Lispを触り始めると、まずいわゆるREPループと対面することになると思います。

簡単に言うと、Lispのコマンドラインみたいなものです。

で、そのコマンドラインがLisp的にどういう風に実現されているかという観点から命名されたのがREPループです(Read -> Eval -> Print ループ)。

                         Lispユーザー   
    
       Textual Representation   Printed Representation
                |                           ^
                |                           |
    ~~ 端末を使ってすべて文字列でユーザーとやりとりします ~~~
                |                           |
      +---------|---------------------------|--------+
      |         |       Lisp World         |        |
      |         V                           |        |
      |   +----------+  +-------- -+  +-----------+  |
      |   |   read   |  |   eval   |  |   print   |  |
      |   +-----+----+  +-------+--+  +-----------+  |
      |         |         ^     |           ^        |
      |         V         |     |           |        |
      |    Lisp Object----+     +-> Lisp Object      |
      |                                              |
      +----------------------------------------------+
  • read関数が入力としてユーザーが打った文字列(textual representation)を読み、その入力文字列の内容で表現されているLisp Objectを作成して出力する。
  • そのLisp Objectをeval関数が”評価(evaluate)”してその結果のLisp Objectを出力する。
  • そのLisp Objectをprint関数が文字列(printed representation)に変換して出力する。

たとえば、(+ 1 2) とrepループに打ち込んだら、次のような処理の流れになります。

       
           "(+ 1 2)"                       "3"
                |                           ^
      +---------|---------------------------|--------+
      |         |       Lisp World         |        |
      |         V                           |        |
      |   +----------+  +-------- -+  +-----------+  |
      |   |   read   |  |   eval   |  |   print   |  |
      |   +-----+----+  +-------+--+  +-----------+  |
      |         |         ^     |           ^        |
      |         V         |     |           |        |
      |       (+ 1 2) ----+     +-> 3 ------+        |
      |                                              |
      +----------------------------------------------+

また、たとえば単独の数字を入力しても”1″ -> read -> 1 -> eval -> 1 -> print -> “1” のように、数字を評価(evaluate)しても元のLisp Objectとしての数字から変化しません。(eval 1) -> 1。単純で分かりやすいですね。

では、コンピュータ的な各種処理を行わせるにはどうするかというと、それはリストを入力してあげることで実現しています。

(OPERATOR arg1 arg2 ...)

リストを評価(evaluate)するときは、上記のように、第一要素を演算子(オペレーター)として扱い、第二要素以降はその演算子への引数として渡すというルールになっているのです。

つまり、プログラムをリストとして入力することになります。
LISP = LISt Processor という名前の由来です。

全知全能の神はいるのか

まぁ、全知全能の神がいるとします。すると矛盾がでてくるんですね。

全能の逆説というらしいです。

全知全能の神が、

「どんな矛も防ぐ盾を出すよ、ほぃっ」

スポポ~ン 無敵の盾登場

「どんな盾も貫く矛をだすよ、ほぃっ」

スポポ~ン 無敵の矛登場

市民1「じゃぁ、神様、その矛でその盾を突いてみたらどうなりますか?」

これは矛盾ですが、私はいままで50年近く生きてきて矛盾を抱えていない人って見たことないんですが、それは置いといて、たとえば、無敵の矛で無敵の盾を突いたとします。ちょっと思いつくのは、

”矛盾なので世界そのものが消える”

こんなんどうでしょう、結果が出ないというのが正解のひとつではないでしょうか?

神様「あれ、面白くないねぇ~、じゃ、無敵の盾と無敵の矛を対決させても、世界が消えないようになぁ~れ!!ほぃっっと」

そしてまた、無敵の矛と無敵の盾を対決させます…

市民A「いくぞ~、そりゃ!」

”こんどは、世界は消えないが、時間が永遠に止まる”

などなど…

複雑系のこととかをちょっと読んだり、量子力学の二重スリット実験のことを読んだりして、いかに矛盾を内包した系を説明するかって大切なんだろうなぁと思っています。