続・LISP インタープリター

9月17日月曜日、曇り時々小雨

なんとか評価器を作り上げるところまで、こぎつけました。

((lambda (x y) (cons y (cons x))) (quote world) (quote hello))

こんな S 式を「評価」すると、

(hello world)

とリストを返してくれる。

どこかに間違いは残っているとおもうし、シンボルにマッピングした lambda 式の評価が動くかは未テストのため、怖さしかない。
けれど、まあよし。

* * *

あとは構文解析器をつくって、標準入出力につないでループにすれば REPL の完成。

いやあ、まだ道は遠い。

* * *

構文解析といえば。

そもそも、元の「小さな LISP インタープリター」の対象としていた LISP は、すべてのアトムが一文字であるというものだった。

講演は通しで見ていないので大きなことは言えないんだけれど、一文字に限定するならもっと攻められるとおもうんだよね。後知恵、後知恵。

講演全編は以下の再生リストから見られる。(準備はしたけれど、未見)

この講演の #1 8分終わりごろに文法が出てくる。

=: set, ': quote, #: lambda, ?: cond, @: atom, +: cons, <: car, >: cdr

これら特殊形式もすべて一文字なので、あとは nil を示す記号を一文字で定めると、 LISP の特徴である () が不要になるのではないか? という妄想。

* * *

スライドでは以下のコードが示されている。

(=('A)(#(XY)(?((@X)Y)(T(+(<X)(A(>X)Y))))))

すべてが一文字という縛りがあるので、空白なしに記号の区切りを解釈できるのである。つまり(ABC)は、AとBとC、三つの記号からなるリストですよと、誤解なく解釈できる。

LISP の別の約束として、リストはリスト終端を示す記号()に、記号を一つずつ左に足したもの、というものがある。つまり(ABC)は単なる略記法で、正式には(A(B(C())))と書くものである。

「組」を作る操作を cons (construct)と呼んでいて、 cons(C, ())が(C())に等しい。
だから(B(C()))は cons(B, cons(C,())) ということになる。同様に(A(B(C())))は cons(A, cons(B, cons(C,()))) になる。

さて、一文字という文法と cons は + だということを思いだすと cons(A, cons(B, cons(C,()))) は +A+B+C()となる。そして終端()を $ と表すことにしてみると +A+B+C$ が(ABC)だ。

この方式で先のスライドのコードを書き直してみると、……

+=++'+A$++#++X+Y$++?++@+X$Y$+T+++<+X$+A+>+X$Y$$$$$$

こうなる。

いや、読めない! 読めないね!(笑)

* * *

知っている人は知っている、これは「逆ポーランド記法」と呼ばれるものだ。

LISP は、すべてがバイナリーオペレーターで組みたてられた世界で、操作が前置される逆ポーランド文法だということ。

* * *

逆ポーランド記法を使うと、操作が最初に確定するので処理効率がよいと教えられた、おぼろげな記憶がある。

けれど実際のところ、世界はバイナリーオペレーターであると確定しているなら、インフィックスだろうがポストフィックスだろうが、構文解析の難しさは変わらない ……かもしれない。(「すべての記号が一文字である」のように、すべての形態素解析が終了している前提で)

これは後日、ちゃんと時間をとって考えてみたい。

この記事が気に入ったらサポートをしてみませんか?