Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2007-12-20

40年前の処理系 PDP-1 Lisp を試してみる

| 05:24 | 40年前の処理系 PDP-1 Lisp を試してみる - わだばLisperになる を含むブックマーク はてなブックマーク - 40年前の処理系 PDP-1 Lisp を試してみる - わだばLisperになる

何となく前から気になっていたPDP-1 Lispを試してみることにしました。

PDP-1 Lispは、LISPの処理系の中でもかなり初期の部類で、1964年に当時高校生だった、L. Peter Deutschが作った処理系です。

その名の通り、PDP-1で動きます。

PDP-1のエミュレータはSIMHというエミュレータ集の中に含まれていることは以前から知ってはいたのですが、しかしさすがにPDP-1ということもあり、きっと動作させるのはかなり面倒なんだろうと思って放置していたのですが、環境が整備されていたこともあり実際に試してみると非常に簡単でした。

とりあえず用意するものとしては、

  1. PDP-1 エミュレータComputer Simulation and History
  2. Lisp for the PDP-1

位のものです。

simhは、ubuntuや、debianではパッケージになっているようです。

PDP-1 Lispの準備

lispswre.zipに同梱のlisp_doc.txtを読んで、必要なものを作成します。

といっても

展開したディレクトリで、

$ cc macro1.c -o macro1
$ macro1 lisp.mac

と実行するのみです。

起動スクリプトの作成

  • lisp.boot
set cpu mdv
load lisp.rim
d extm_init 1
run

d tw 7777
c

d tw 400
c

d ss 2
save lisp.sav
c

として作成してみます。

起動用スクリプトの作成

  • pdp-1-lisp
#!/bin/sh

cd /share/sys/emu/PDP-1.emu/
./pdp1 ./lisp.boot

適当に起動用のスクリプトを作ってみます。

とりあえず、これで遊べます。

(plus 3 3) |スペース| |改行|
;=> 6

式を入力して、スペースを入力し改行すると評価される様です。

Emacsと連携させてみる。

run-lispで使えるように適当に設定してみます。

(setq inferior-lisp-program "~/bin/pdp-1-lisp")

等々

inferior-lisp-modeだと、式の後の一文字スペースが足りないので、若干無理矢理ながら関数に細工します。といっても一文字空白を挿入してから改行するようにするだけです。

(defun lisp-eval-region (start end &optional and-go)
  "Send the current region to the inferior Lisp process.
Prefix argument means switch to the Lisp buffer afterwards."
  (interactive "r\nP")
  (comint-send-region (inferior-lisp-proc) start end)
  (comint-send-string (inferior-lisp-proc) " \n")
  (if and-go (switch-to-lisp t)))

不正な入力があると、PDP-1ごと落ちますが、simhのモニタに落ちたらcを入力すると復帰します。

SIMHの終了には、Control-Eを入力し、モニタに落ちて、qの入力で終了します。

Emacs内部の場合、Control-Qでエスケープする必要ありです。

色々探って遊ぶ

  • Hello, World!
(print (quote Hello\,\ World!))
;=> Hello, World! 

とりあえず、Hello, World! 文字列というものは無いようなので、シンボルです。シンボルの大文字と小文字を区別するというのが意外です。

  • 関数を定義してみる

関数の定義する方法が全く分からず、結構悩みました。

シンボルは、oblistというリストに格納されていて、起動時には、

(atom car cdr cond cons eq gensym greaterp list minus 
numberp stop prin1 quotient rplaca rplacd terpri prog return
 go setq sassoc plus times logand logor xeq loc null quote
 lambda apval subr expr fsubr fexpr t oblist read eval
 print nil) 

となっていてこれで全部です。

標準で使える関数もこのなかにあるということになるのですが、defineとかcsetqとかそれらしきものはなく、結構悩んだのですが、どうにもならないので、マニュアルを探したところPDFのマニュアルがありました。

これによると、どうやら関数は、rplacdを使って定義するらしいのです。

どういう仕組みなのかというと、シンボルのcdrがシンボルのプロパティになっていて、

(cdr (quote foo))
;=> nil

のようになります。それで、シンボルのCDR部に関数定義を詰め込むと名前に関数が設定できるという仕組みのようです。こんなの良く考えつくなと感心。

ということで、定番のfibは、

(rplacd (quote fib)
	(quote 
	 (expr
	  (lambda (x)
	    (cond ((greaterp 2 x) x)
		  (t (plus (fib (plus x (minus 1)))
			   (fib (plus x (minus 2))))))))))

(fib 10)
;=>25 (8進数)

と定義できました。再帰も使えます。引き算用の関数はないので負数を足すということになっていて、lesspもないのでgreaterpを逆転させてます。数字は8進数です。

exprというのは、固定の引数を取る関数であることを表わしています。他にfexprというのもありこっちは、可変引数です。

  • reverse
(rplacd (quote reverse)
	(quote (expr
		(lambda (lst)
		  (prog (l res)
		     (setq l lst)
		     loop 
		     (cond ((null l) (return res)))
		     (setq res (cons (car l) res))
		     (setq l (cdr l))
		     (go loop))))))

progでreverse

  • mapcar
(rplacd (quote mapcar)
	(quote (expr
		(lambda (f lst)
		  (prog (l res)
		     (setq l lst)
		     loop
		     (cond ((null l) (return (reverse res))))
		     (setq res (cons (f (car l)) res))
		     (setq l (cdr l))
		     (go loop))))))

(print
(mapcar (quote (lambda (x) (times 3 x)))
	(quote (1 2 3))))
;==>
;(3 6 11) 

なんとなくmapcarを作ってみたり。

なんとなくまとめ

「空リストが偽を表わす」というのはどの辺りから始まったのかというのは、あまりはっきりしていないようです。

最初期のLisp 1.5でも真と偽は、TとFとして定義されている様子て、「空リストが偽を表わす」ことも肯定的に捉えられてはいなかったようで、Interlisp文化以外のところでは、むしろ否定的に考えられていたようです。

それで、このPDP-1 Lispはどうなのかと言えば、()も、(quote ())もnilで偽ということになっています。

(cdr ni)はどうかといえば、(apval nil)がでてきます。これは、nilのプロパティってことなんでしょう。

ちなみに(cdr nil)としても、エラーにならず、nilを返すというのは、Interlisp由来らしいのですが、処理系の発展の流れからすると、PDP-1 Lisp -> BBN Lisp -> Interlispという流れで、Peter Deutschがからんでいるので、もしかしたらこの辺は、この人由来なのかしらと、ぼんやり考えたりしました。

ゲスト



トラックバック - http://cadr.g.hatena.ne.jp/g000001/20071220