#:g1: Lispとエディタ (1)

Posted 2015-06-26 14:05:53 GMT

 LispとエディタといえばEmacsですが、Emacsは熟練しないと使い熟せないとか、EmacsばかりがLispエディタじゃない!等の話はよく耳にします。
といっても、そんな話にそれ以上の考察もなく同じ所をぐるぐる廻っているだけ、という感じがしていました。
そこで一つLispとエディタの関係について調べて考察してみようかなと思った次第です。

最初期のLispとエディタ (1960年頃)

まず、最初のLispといえば、LISP 1.5ですが、どうもバッチ方式のようです。
print以外にpunchなんて関数もあったりしますのでパンチカードでの入出力は標準だった様子。
LISP 1.5をIBM 7094のエミュレータで動かしてみた感じでもそんな感じですが、IBM 7094ので主に使われたエディタってなんなんでしょうね。

初の対話式 Lisp (1964年頃)

初の対話式Lispとなると、どうも当時17歳のL Peter Deutsch氏が開発したPDP-1 Lispのようです。
BASICも1964年あたりですが、対話式プログラミング環境としては最初の一つなのかもしれません。
PDP-1で利用されたエディタですが、Daniel L. Murphy氏が開発したTECOだと思われます。
TECOは、Emacsの先祖として有名ですが、Unix方面でいうと、edの先祖のqedの元になったものがtecoなので、Emacsもviも元はtecoともいえます。
このtecoで1964年あたりにLispの編集支援機能が作られていたかどうかはちょっと分かりませんでした。

Binford editor (1969年頃)

今から46年前の1969年9月24日のMacLISPの開発ニュースによれば、

THE S-EXPRESSION EDITING SYSTEM OF TOM BINFORD IS
NOW A REGULAR PART OF THE SYSTEM. A MEMO SHOULD BE
COMING OUT SOON ON ITS USE; IT IS VERY MUCH LIKE
USING TECO WHILE IN LISP.

ということなので、S式エディタとしてTom Binford氏作のBinfordエディタがMacLISPに統合されたようです。
TECOみたいなものとあるので、この辺りではTECOが主流だったことが分かります。
この時代には、TECO ⇔ Lisp処理系で連携する機能もあるようですが、資料があまり残っていないようなので詳細は不明です。

とりあえずBinford エディタは、現在でもMacLISPで動かすことができるので機能を確認してみましょう。

Binfordエディタのコマンド

Binfordエディタのコマンド MacLISPのマニュアルによれば、はこんな感じです。

$Escを表わし、$$というのは、連続2回入力を表わします。
TECOもそうですが、終端としては、$$が標準だった様子。
コマンドの確定には、Space+改行ですが、複数のアイテムを取れる場合には$$で終端します。 数引数は前置され、-は意味が反転されます。
また、カーソル位置は、$$で表現されます。

移動系

移動系は数引数が前置可能で、回数分の繰り返しになります。(例.4F等々)

仮想括弧

仮想括弧は独自の概念ですが、binford editorでは、まず仮想的な括弧を挿入し、()コマンドで確定させるという方式です。
仮想括弧は、|%I(%||%I)%|で表わされます。

マーク

表示系

セッション例

コマンドは大体分かったので、実際にfibでも定義してみましょう。
色々試行錯誤してみましたが、editでエディタを立ち上げてから何かするというよりは、REPLにざっと適当に入力したものをeditで修正するのが一番楽なようです。
以下では、そんな感じでfibを定義してみます。

ざっと定義(1-の所でミスありだがeditで修正する予定)

(defun fib (n) (if (< n 2)n(+ (fib (1- ))(fib (- n 2)))))
FIB 

fibを編集

(edit fib)

s 1- $$1-を探す

s 1- $$

< N 2) N (+ (FIB (1- $$ )) (FIB (- N 2)))

i n $$nを挿入

i n $$

< N 2) N (+ (FIB (1- N $$ )) (FIB (- N 2)))

連続入力も可能

j f f f f

$$ EXPR (LAMBDA (N) (IF (< N 2) N (+ (FIB (1- N)) (FIB (- N 2))))))

EXPR $$ (LAMBDA (N) (IF (< N 2) N (+ (FIB (1- N)) (FIB (- N 2))))))

EXPR ( $$ LAMBDA (N) (IF (< N 2) N (+ (FIB (1- N)) (FIB (- N 2))))))

EXPR (LAMBDA $$ (N) (IF (< N 2) N (+ (FIB (1- N)) (FIB (- N 2))))))

ifcondに変更してみる例

ifを探す

s if $$

EXPR (LAMBDA (N) (IF $$ (< N 2) N (+ (FIB (1- N)) (FIB (- N 2))))))

condに置き換え

-ki cond

EXPR (LAMBDA (N) (COND $$ (< N 2) N (+ (FIB (1- N)) (FIB (- N 2))))))

仮想カッコを挿入

( 

EXPR (LAMBDA (N) (COND |%I(%| $$ (< N 2) N (+ (FIB (1- N)) (FIB (- N 2))))))

2式右へ移動

2r 

EXPR (LAMBDA (N) (COND |%I(%| (< N 2) N $$ (+ (FIB (1- N)) (FIB (- N 2))))))

仮想コッカを挿入

) 

EXPR (LAMBDA (N) (COND |%I(%| (< N 2) N |%I)%| $$ (+ (FIB (1- N)) (FIB (- N 2))))))

仮想カッコを挿入

( 

EXPR (LAMBDA (N) (COND |%I(%| (< N 2) N |%I)%| |%I(%| $$ (+ (FIB (1- N)) (FIB (- N 2))))))

tを挿入

i t $$

EXPR (LAMBDA (N) (COND |%I(%| (< N 2) N |%I)%| |%I(%| T $$ (+ (FIB (1- N)) (FIB ( - N 2))))))

1式右へ移動

r 

EXPR (LAMBDA (N) (COND |%I(%| (< N 2) N |%I)%| |%I(%| T (+ (FIB (1- N)) (FIB (- N 2))) $$ )))

仮想コッカを挿入

) 

EXPR (LAMBDA (N) (COND |%I(%| (< N 2) N |%I)%| |%I(%| T (+ (FIB (1- N)) (FIB (- N 2))) |%I)%| $$ )))

仮想括弧を実体化

() 

EXPR (LAMBDA (N) (COND ((< N 2) N) (T (+ (FIB (1- N)) (FIB (- N 2)))))) $$ )

終了

q 

REPLに抜けて関数を実行

* 
(fib 10.)
55 

関数の本体を後でまとめて定義してみる

仮想括弧を入力して確定するのが結構面倒なのですが、何か楽な方法はないかと考えてみました。
ivを使えば、Lispの式が挿入できるので、これを使ってみた例です。

(defun fib (n)n)
FIB 

(edit fib) (SLURPED EDIT FASL)

$$ EXPR (LAMBDA (N) N)) 80pw

$$ EXPR (LAMBDA (N) N)) 2r

EXPR (LAMBDA (N) N) $$ ) 2b

EXPR (LAMBDA (N) $$ N)) k

EXPR (LAMBDA (N) $$ )) iv '(if (< n 2)n(+))

EXPR (LAMBDA (N) (IF (< N 2) N (+)) $$ )) b

EXPR (LAMBDA (N) (IF (< N 2) N (+) $$ ))) b

EXPR (LAMBDA (N) (IF (< N 2) N (+ $$ )))) iv '(fib (1- n))

EXPR (LAMBDA (N) (IF (< N 2) N (+ (FIB (1- N)) $$ ))))

iv '(fib (- n 2))

EXPR (LAMBDA (N) (IF (< N 2) N (+ (FIB (1- N)) (FIB (- N 2)) $$ ))))

式指向と行指向

 以上、Binfordエディタを試してみたり解説してみたりしましたが、既に現在のEmacsでのLispの編集と大枠では同じことが可能であるのが分かるでしょうか。
特長としては下記のような事項が挙げられます

Lispでは何故、式指向のエディタが望まれたのかですが、Lisp自体が式指向であるからではないかと思います。
式が値を返すということは、思考単位にしろデバッグの単位にしろ式が意味単位となり、これを相手にしなければなりません。
Lispの意味は行単位ではありません。行で区切られても意味単位ではないので不便です。
行エディタで快適に編集できるプログラム言語というものは、文が主であったりして、値は何かに代入され、その代入されるという表現も大概行に収まります。

ということで、Lispの編集には式指向であることが求められのですが、式指向エディタについては、Interlisp方面でさらに進化がみられるようなので、そちらも調べてみたいところです。

ファイルへの出力は?

ファイルへの書き出しについてはいまいち不明なのですが、Lispファイルの整形には、grindというプリティプリントのプログラムが良く使われていました。
これで一括で出力することも可能だったのではないかと思われます。

まとめ

 最初期のエディタから、式指向のエディタが出始めた約60年前〜50年前あたりを考察してみました。

上記「式指向と行指向」でも述べましたが、Lispでは式の表現を扱う手段が必要とされ、半世紀前には既にそれが実践されていたことも分かります。
しかし行指向の言語がメジャーであるために、半世紀経過した現在でさえ、(行指向エディタでは)Lispは書きにくいのが問題である、というような話も良く耳にします。
根本的には、式というものが理解されていないのが原因ではないでしょうか。
考えてみれば、C/JavaのようにLispをぶらさがり括弧で記述するのも、どうにか行指向に合せようとした結果のような気もしますが、括弧の対応など式の整合性を取る作業は人力でやらないというのが半世紀前に出ていた結論な気がします。

文より式をメインとするプログラミング言語がどんどん増えてきましたが、式指向の考え方がメジャーになっていくことを期待したいところです。

次は、Emacsが出始める40年位前を考察してみたいと思います。


HTML generated by 3bmd in SBCL 1.2.12

comments powered by Disqus