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 |

2008-05-08

CADRでFLAVORS

| 16:10 | CADRでFLAVORS - わだばLisperになる を含むブックマーク はてなブックマーク - CADRでFLAVORS - わだばLisperになる

CADRエミュレータで何かしようと思いつつも前回からまた一ヶ月経ってしまいました。

最近CLOSのような、LISP上でのOOPになんとなく興味があるのですが、CADRには、CLOS以前のflavorsというOOPの枠組がありました。

よくRubyなどで、mixinとかいう用語が使われますが、この用語は、確かflavorsに由来していたと思います。

アイスクリームのトッピングに由来した用語なのですが、flavorsという名前自体、そのトッピングのことを指してるみたいです。

とりあえず、何から始めたら良いか良く分からないので、ポール・グレアム著のANSI CLのCLOSの章をなぞってみることにしました。

とりあえず、構造体とクラスを比較してみる、という内容なのですが、defstructの細かいところが、CLとLisp Machine Lispで違っていたりして、それもまた乙です。

とりあえず、CLの構造体だとこんな感じです。

;; CL
(defstruct rectangle
  height
  width)

(defstruct circle
  radius)

(defun area (x)
  (cond ((rectangle-p x)
         (* (rectangle-height x) (rectangle-width x)))
        ((circle-p x)
         (* pi (expt (circle-radius x) 2)))))

(let ((r (make-rectangle)))
  (setf (rectangle-height r) 2
        (rectangle-width r) 3)
  (area r))
;=> 6

自動で、rectangle-widthのようなアクセサを作ってくれて、rectangle-pのような述語も作成してくれます。

次にLisp Machine Lispでの構造体でのバージョンです。

;; Lisp Machine Lisp
(defstruct (rectangle :named)
  rectangle-height
  rectangle-width)

;; アクセッサはフルネームじゃないと駄目
;; namedにしないと、
;; (typep obj 'rectangle)とか効かないので、
;; namedで作らないとrectangle-pのようなものが作れないらしい。

(defstruct (circle :named)
  circle-radius)

;; piは定数ではないので定義
(defconst pi 3.141592653589793238)

;; 自動で、述語を作ってくれないので自作
(defmacro make-pred (name)
  `(defun ,(intern (string-append (string name) "-P")) (obj)
     (typep obj ',name)))

(make-pred rectangle)
(make-pred circle)

(defun area (x)
  (cond ((rectangle-p x)
         (* (rectangle-height x) (rectangle-width x)))
        ((circle-p x)
         (* pi (expt (circle-radius x) 2)))))

(let ((r (make-rectangle)))
  (setf (rectangle-height r) 2)
  (setf (rectangle-width r) 3)
  (area r))
;=> 6

そして、Lisp Machine LispのFlavorsで

;; Lisp Machine Lisp
(defflavor rectangle (height width) ()     
  :gettable-instance-variables
  :settable-instance-variables)

(defflavor circle (radius) ()
  :gettable-instance-variables
  :settable-instance-variables)

(defmethod (rectangle :area) ()
  (* (funcall-self ':height) (funcall-self ':width)))

(defmethod (circle :area) ()
  (* pi (expt (funcall-self ':radius) 2)))

(let ((r (make-instance 'rectangle)))
  (<<-- r
        (':set-height 2)
        (':set-width 3)
        (':area)))
;=> 6

ざっとした説明ですが、まず、キーワードに一々クオートが付いています。

これは、Lisp Machine Lispでは、CLのようにキーワードパッケージがあって、そのシンボルの評価結果が自分自身となるようなものではなく、ただの目印的なものなので、クオートが必要になります。

次に、defflavorですが、これは、CLOSのdefclassに相当します。

書式は、

(defflavor クラス(フレイバー)名 (スーパークラス)
  ...)

のような感じで、

:gettable-instance-variables

:settable-instance-variables

:inittable-instance

は値を取得/設定/初期化できるようにする指示で、デフォルト値も設定できます。

とりあえず、フレーバーを作ったら、

(setq r (make-instance 'rectangle))

(<- r ':set-width 3)

のようにして、値を設定できたりします。

rというオブジェクトに:set-widthと3というメッセージを送るのですが、

(funcall r ':set-width 3)

でも良かったりするみたいです。

ちなみに<-は後に、sendという名前になったようです。

set-〜というところは、
settable-instance-variablesをすると自動的に:set-〜で値を設定することができるようになります。

それで、defmethodですが、

(defmethod (フレーバー キー?) (引数)
  ...)

となり、CLのdefmethodとはちょっと違っています。

呼び出し方ですが、

(<- r ':area)

のようになるようです。

funcall-selfですが、defmethod内では自身を指すselfという変数が使えるので、これは、(<- self ...mesg)と同じことのようです。

CLOSのように(area r)とは書けないみたいでなんですが、初期のFlavorsの試行錯誤の後、「関数呼び出しの形とメソッド呼び出しの形を一緒にしたら良いんじゃないか?」というアイディアが現われて形が統合されたらしいです。

<<--は、(progn (<- ..) (<- ..))に展開されるマクロで上の例は、

(let ((r (make-instance 'rectangle)))
  (<- r ':set-height 2)
  (<- r ':set-width 3)
  (<- r ':area))

と同じです。

まとめ

という感じで、自分も全然分かっていないので、解説らしい解説にもなっていないのですが、色々いじって遊んでみようと思っています!

2008-04-03

またふらふらとCADRでなにかする

| 19:08 | またふらふらとCADRでなにかする - わだばLisperになる を含むブックマーク はてなブックマーク - またふらふらとCADRでなにかする - わだばLisperになる

メインの環境を64bit Linuxにしてから、CADRエミュレータが上手く動かなくなっていたので放置していたのですが、Ubuntuの場合ia32-libsをインストールすれば、面倒もなく32bit版で動くことが分かったので、またいじり始めてみることにしました。

以前のエントリでは、ダウンロードから導入、ちょっとした開発環境の説明を書きました(CADRカテゴリーに纏めてあります)が、

今年は、もう一歩踏み込んでみたいところ。

目標としては、Flavorsなどを使ってプログラミングするところ位まで探究できたら良いなと思っています。

配布されているMIT CADRエミュレータの場合、初期のマニュアルに説明のある機能が無かったりしますので、結構初期のLisp Machine Lispのようです。

とりあえず今日は久し振りに使ってみるということで、前々から試してみたかった、ZMACSへのコマンドの追加を試してみたいと思います。

ZMACSは、Lispマシンで動くEMACSで、オリジナルのEMACSとほとんど同時期の1976年に開発がスタートしたようです。

最初は、EINE(Eine Is Not EMACS)という名前で、その後、ZWEI(Zwei Was Eine Initially)という名前になり、Zmacsへ、という流れになります。

Lispマシンは全面的にLispで記述されているので、当然その上で動くZMACSもLispで記述されています。LISPで記述されているということは、最初からLISPで拡張可能なわけで、恐らくLISPで拡張可能なエディタとしては、ZMACSが一番最初のものなのではないでしょうか。Multics EMACSは、1978年で、Multics EMACSの作者もZMACSの方が先に存在してたと言ってましたし…。

それはさておきZMACSの拡張コマンドですが、DEFCOMという対話操作拡張用のマクロが用意されているのでそれを使ってみます。

作るコマンドですが、自分は、普段ダブルクオートをM-"のキーバインドで、対で入力しています。

EMACSでは、幾つかこの様な入力方法を実現する方法があるのですが、ZWEIにもCOM-MAKE-()という、括弧を対で入力する関数があるので、これをちょっといじって作ってみました。

この関数は数引数を受けとることにより、任意の式をまたいで囲むことができます。

(pkg-bind "zwei"
  (DEFCOM COM-MAKE-/"/" "Insert matching delimiters, putting point between them.
With an argument, puts that many s-exprs within the new /"/"." ()
    (LET ((OPEN #/") (CLOSE #/")
          (MOVER 'FORWARD-SEXP) (POINT (POINT)))
      (DO ((CH (LDB %%CH-CHAR *LAST-COMMAND-CHAR*))
           (L *MATCHING-DELIMITER-LIST* (CDR L)))
          ((NULL L))
        (COND ((OR (= CH (CAAR L)) (= CH (CADAR L)))
               (SETQ OPEN (CAAR L) CLOSE (CADAR L) MOVER (CADDAR L))
               (RETURN T))))
      (LET ((BP (IF *NUMERIC-ARG-P*
                    (OR (IF (EQ MOVER 'FORWARD-SEXP)
                            (FORWARD-SEXP POINT *NUMERIC-ARG* NIL 0 NIL T T)    ;No UP
                          (FUNCALL MOVER POINT *NUMERIC-ARG*))
                        (BARF))
                  POINT)))
        (AND (MINUSP *NUMERIC-ARG*) (PSETQ BP POINT POINT BP))
        (INSERT BP (IN-CURRENT-FONT CLOSE))
        (INSERT-MOVING POINT (IN-CURRENT-FONT OPEN))
        DIS-TEXT)))
  )

ちょっとした説明

  • EMACSとZMACSの違い

上記のコードを眺めるとGNU Emacsとは結構違っていることが分かると思います。Hemlockや、LispWorksのエディタ、Climacs等これに近いのですが、恐らく、ZMACSから影響を受けていて、ZMACS系とも呼べると思います。

  • pkg-bind
    • ボディ部は指定したパッケージ内で評価されます。上記の場合、"ZWEI"パッケージ内で評価されています。Lispマシンの場合、ファイルの一行目にパッケージを記述することで、指定することができるのですが、この方法を発見したので試しに使ってみています。

それで、定義した関数をどうっやってキーバインドに割り付けるかですが、

割り付けには、SET-COMTABやSET-COMTAB-RETURN-UNDOを使用します。

自分は、初期化ファイルで設定するので、ログアウトしたらアンドゥされるように、SET-COMTAB-RETURN-UNDOを使ってみています。

(login-eval
 zwei:(set-comtab-return-undo *standard-comtab* '(#^C/" com-make-/"/"))) ;^Cはコントロール文字

という風にホームディレクトリのlispm.initに記述すれば、M-"でcom-make-""が呼び出されるようにログイン時に初期化されます。

ちなみに、パッケージの指定方法が不思議な感じになっていますが、こういう風にも書けたみたいです。

zwei:(set-comtab-return-undo *standard-comtab* '(#^C/" com-make-/"/"))
=>
(zwei:set-comtab-return-undo zwei:*standard-comtab* '(#^C/" zwei:com-make-/"/"))

ということのようなのですが詳細はまだ、良く分かっていません。pkg-bindの略記方法なのかもしれませんが、便利といえば便利なような。

という感じで、ふらふらとしばらくMIT CADRを使ってみようと思います。

2007-07-19

CADRエミュレータ (4) Lispの開発環境

| 23:09 | CADRエミュレータ (4) Lispの開発環境 - わだばLisperになる を含むブックマーク はてなブックマーク - CADRエミュレータ (4) Lispの開発環境 - わだばLisperになる

とりあえず、外部とのファイルのやりとりもできるようになりました。

折角のLispマシンなので、Lispを書いて遊びたいところだと思うので、CADRのLisp開発環境について書きたいと思います。

この辺からは、自分がLispの開発の経験がある訳でもなくLisp自体に詳しい訳でもないので、詳しいことは全く分かりませんので、かなり適当なことを書いている可能性も高いですが、とりあえず、自分が遊んでみたところを書いてみたいと思います。

コードを書く

これはZmacs上でEmacsと同じ感覚でファイル作成/編集ができます。Emacs上でのLispコードの操作ということに関しては、70年代のITS Emacs、Zmacsの時点でほぼ完成しているということなのかもしれません。

インタラクティブに書きたいんじゃ

これは、編集中のコードを評価することによってEmacsのinferior lisp modeの様な感覚でコードを書くことができるかと思います。評価された結果は、エコーエリアに表示されます。

Eval Defun (Control-Shift-E (Control-Hyper-E))

で、式を評価、

Compile Defun (Control-Shift-C (Control-Hyper-C))

で、式をコンパイルのようです。

評価した結果にエラーがある場合は、デバッガが起動します。デバッガから抜けるには、C-zを押します。

という感じで、自分などは、大したものを書く訳でもなく、書けるわけでもないので、エディタ上から式が評価できるだけで十分遊べます。

ヘルプ

とりあえずのところとしては、

Documentation (Control-Meta-?)

があります。

Control-Meta-?を押して実行すると、

Doc A,C,D,L,V,W,<space>,?:

となるので、適宜調べたい内容に応じてキーを選択します。

AとspaceはAproposの実行 (Emacsでもapropos)

Cは、Document Command (Emacsでのdescribe-key)

D、Describe Command (Emacsでのdescribe-function)

L、詳細不明です。

V、Variable 変数のApropos

W、Where Is / どのキーコンビネーションに割り当てられているか

という感じです。

他にも、M-.等々Emacsでもお馴染の機能があるので、試してみると面白いかと思います。

2007-07-16

CADRエミュレータ (3) ホスト上のファイルを読み書きする

| 23:08 | CADRエミュレータ (3) ホスト上のファイルを読み書きする - わだばLisperになる を含むブックマーク はてなブックマーク - CADRエミュレータ (3) ホスト上のファイルを読み書きする - わだばLisperになる

CADRエミュレータは単体でも遊べますが、作成したファイルなどをエミュレータ外部に持ち出せるとより楽しく遊べます。

サーバの導入

エミュレータの配布サイトでは、Linux上で動くCADR用のファイルサーバ?がありますので、ダウンロードして設置します。

Retrocomputing - MIT CADR Lisp Machines:

http://www.unlambda.com/cadr/index.html

のページのChaosnet server tar fileをダウンロードしuntarします。

展開されたchaosdというディレクトリの中にコンパイル済みのLinux用のバイナリがありますので、

./chaos

./server

の順で起動させます。

起動は、展開ずみのディレクトリにcdして実行する必要があるようです。

(自分は、毎回起動が面倒なので、シェルスクリプトにして実行しています。)

サーバが起動された状態で、usimを起動し、CADRから接続を試みます。

配布されている状態では、アドレスは設定済みになっていますので、サイトの例と同じく、CADRエミュレータより、

(login 'foo t)
(si:set-sys-host "server" ':unix 0404 "//")

と実行し、CADRにログインした後にサーバと接続します。

ホスト上のファイルの読み書き

ホスト上のファイル名ですが、server://foo//bar//baz.quuxの様になります。

"/"が二重になっていますが、"/"はCADRではエスケープキャラクタとなっているので、二重に表現する必要があります。

読み書き時の初回時には、接続のため、ユーザ名とパスワードを尋ねてきますので、ホストでのユーザ名 <スペース> そのユーザのパスワードを入力します。

以上、ホスト上のファイルの読み書きについて書いてみました。

(si:set-sys-host "server" ':unix 0404 "//")

等々は、一々入力するのも面倒です。

自分は、スクラッチファイルを適当に容易して、Zmacs上から式をEvaluate Defun(Control-Hyper-E、どういう訳かエミュレータではC-Sh-Eを押すとこの組み合わせが発生)で評価してみていますが、楽ができるので結構お勧めです。

2007-07-14

CADRエミュレータ (2) ユーザ環境設定編

| 23:08 | CADRエミュレータ (2) ユーザ環境設定編 - わだばLisperになる を含むブックマーク はてなブックマーク - CADRエミュレータ (2) ユーザ環境設定編 - わだばLisperになる

CADRはシングルユーザシステムですが、ユーザ毎に環境を設定して切り換えて使用することはできます。

(login 'foo)

とすることで、ユーザfooでログインできます。

何らかの理由で、環境設定初期化ファイルを読み込ませたくない場合は、

(login 'foo t)

とします。

(logout)

でログアウトします。

ホームディレクトリの作成

fooでログインした場合、ホームディレクトリfooにある。lispm.initを読み込み実行します。

恐らくホームディレクトリの場所の指定は様々あると思うのですが、良く分からないので、とりあえず、ホームディレクトリを作成し、その中にlispm.initを作成することによってユーザ環境を設定する方法を書きます。

とりあえず、ログインして作業を開始します。

(login 'foo t)

として、初期化ファイルを読み込まずログインし、F2 f(F2キーのあとで、Fを押す)とFile System Editorが起動するので、Tree edit rootを左クリック。しばし待ち、

>*.*.*

の上で右クリック。(ディレクトリのパスセパレータは、">"です)

Directory operationsメニューが表示されるので、Create Inferior Directoryを選択

名前の入力を促されるので、ユーザIDと同じ名前を入力するとディレクトリが作成されます。

初期化ファイルの作成

ホームディレクトリが作成されたので、ユーザの初期化ファイルを作成してみます。

一旦

(logout)

でログアウトし、

(login 'foo)

でログインし直します。

(ed)

と入力すると、Zmacs(Lisp Machine版のEmacs)が起動します。

ホームディレクトリにいるので、Emacsと同様に、C-x C-fとし、lispm.initを作成します。

初期化ファイルについては情報が少なく詳細は不明ですが、自分が適当に探って作成してみたものを置いてみます。

ウェブから入手できる初期化ファイルとしては、http://www.unlambda.com/lisp/mit.page

で配布されているファイルの中に、David Moon氏の初期化ファイルがあります。(moon/moon.lispm)

自分もそれを参考に作成してみました。

※αとなっている場所は、制御文字^Bで、εは、^Fです。

入力に関しては、Emacsと同様に^Q^B等で入力できます。

;-*- Mode:LISP; Package:USER; Base:8.-*-

(login-setq base 10.			; 表示用の基数を10進数に設定
	    ibase 10.			; 入力用の基数を10進数に設定
	    user-id "g000001")		; ユーザID

;; キーバインドのカスタマイズ
(login-eval zwei:(set-comtab-return-undo *standard-comtab* 
					 '(#α/m com-insert-crs         ; C-mとReturnとで同じ振舞い
					   #α/i com-indent-for-lisp    ; C-iとタブとで同じ振舞い
					   #α/h com-tab-hacking-rubout ; C-hでRubout(Backspace)
					   #ε\sp com-just-one-space))) ; C-M-Spaceで、Just one Space
(login-eval zwei:(set-comtab-return-undo *completing-reader-comtab* 
					 '(#α/m com-complete-and-exit))) ; エコーエリア?でもC-mが使えるようにしてみる(中途半端)

;;
(ed ">g000001>gazonk.del")                   ; ログインするとすぐZmacsが起動

2007-07-13

CADRエミュレータ (1) デモ編

| 23:07 | CADRエミュレータ (1) デモ編 - わだばLisperになる を含むブックマーク はてなブックマーク - CADRエミュレータ (1) デモ編 - わだばLisperになる

CADRエミュレータについては、分かりやすい導入の手引があります。

A quick first tour of the CADR lispm using usim

http://labs.aezenix.com/lispm/index.php?title=CADR_First_Tour

ここのサイトさんにはlispm関係の情報が色々まとまってるんですが、スパムがひどいみたいで、現在フロントページから内容が俯瞰できない様子です。

動作するプラットホームとしては、Windows、MacOSX、Linux等がありますが、Linuxがメインの開発プラットホームの様子で、ホストと通信してファイルを読み書きできたりもするので個人的にはLinuxがお勧めです。

手引の中で、

 (hacks:worm)

とありますが、この方法以外にもリスナーで

(demo)

と実行すると、デモを選択するプログラムが起動し、色んなデモプログラムが選択できるのでお勧めです…が良く固まる気もします…。

最初の起動では、かなり長く待たされたと思いますが、これを短縮する、ウォームブートという起動方法があります。詳細は、READMEに解説されていますが、手順としては、

./usim -S

で起動し、日付を入力するところまで完了させ、ターミナル上で、^Cを二回押しエミュレータを終了させます。するとusim.stateというファイルができ、これに状態が記録されているので、次回以降、

./usim -w

と入力することによって、さっと起動できるようになります。

2007-04-26

CADRでSICP 1.6

| 21:37 | CADRでSICP 1.6 - わだばLisperになる を含むブックマーク はてなブックマーク - CADRでSICP 1.6 - わだばLisperになる

CADRでSICP Exercise 1.6.に挑戦 - Structure and Interpretation of Computer Programs

Exercise 1.6
ifが特殊形式である必要性について

(defun new-if (predicate then-clause else-clause)
  (cond (predicate then-clause)
	(T else-clause)))
のように新しいifを定義する。
これが、
(defun sqrt-iter (guess x)
  (new-if (good-enough-p guess x)
          guess
	  (sqrt-iter (improve guess x)
	             x)))
のように使われた場合、どのように動くかを考察せよ、
というような問題。
解答
特殊形式でないと、then部、else部ともに評価を終えた
後で、分岐を評価しようとするので、自分を呼び出す再
帰が使われている場合、無限ループになってしまう。
そして全然質問とは関係ないが、ずっと解答と書いてい
たつもりが、回答となっていたことにはたと気付いたの
で全部直した。

自分のための理解補助コード:
(defun foo (x)
  (if (zerop x)
      'zero!
    (princ "foo!")))

(foo 0)
-> ZERO!

(defun bar (x)
  (new-if (zerop x)
	  'zero!
	  (princ "foo!")))

(bar 0)
->ZERO!
と共にfoo!もプリントされる。

2007-04-25

CADRでSICP 1.5

| 20:03 | CADRでSICP 1.5 - わだばLisperになる を含むブックマーク はてなブックマーク - CADRでSICP 1.5 - わだばLisperになる

CADRでSICP Exercise 1.5.に挑戦 - Structure and Interpretation of Computer Programs

Exercise 1.5
(defun p ()
  (p))

(defun test (x y)
  (if (= x 0)
      0
    (if (functionp y)
	(funcall y)
      y)))
とした場合、
(test 0 #'p)
の評価が正規順序の評価と、作用的順序の評価でどう違っ
てくるかを説明せよ。
解答
正規順序だと、(p)が実行されることになるので、無限
ループになるんではなかろうか。ということで、(p)の
評価が終らず結果が出せない。
ちなみにCADRでは、PDL Overflowになる。
作用的順序だと、(p)は評価する必要がないので0が返さ
れ終了する。

CADRでSICP 1.4

| 20:01 | CADRでSICP 1.4 - わだばLisperになる を含むブックマーク はてなブックマーク - CADRでSICP 1.4 - わだばLisperになる

CADRでSICP Exercise 1.4.に挑戦 - Structure and Interpretation of Computer Programs

Exercise 1.4
演算子が合成式でも評価モデルが使えるかを観察せよ。
Scheme:
(define (a-plus-abs-b a b)
  ((if (> b 0) + -) a b))

解答
Lisp Machine Lispというか、Lisp-2だと
(defun a-plus-abs-b (a b)
  (funcall (if (> b 0) #'+ #'-) a b))
となると思う。
(a-plus-abs-b 3 -3)
-> 6.
にはなるけど、これは演算子が合成式ってことになりま
せんわよね。

CADRでSICP 1.3

| 00:15 | CADRでSICP 1.3 - わだばLisperになる を含むブックマーク はてなブックマーク - CADRでSICP 1.3 - わだばLisperになる

CADRでSICP Exercise 1.3.に挑戦 - Structure and Interpretation of Computer Programs

Exercise 1.3
3つの数のうち、大きい方2つの自乗の和を返す手続きを
つくれ。
解答
(defun sum-square-largest-2 (x y z)
  (if (and (<= x y) (<= x z))
      (+ (* y y) (* z z))
    (sum-square-largest-2 y z x)))

(defun sum-square-largest-2 (x y z)
  (cond ((and (<= x y) (<= x z))
	 (+ (* y y) (* z z)))
	((and (<= y z) (<= y z))
	 (+ (* z z) (* x x)))
	((and (<= z x) (<= z y))
	 (+ (* x x) (* y y)))))

偶々回答の前にJoe Marshall氏の小ネタ(日本語訳)を見てしまったため、

逆に普通の答え方の方がややこしく感じられるという罠。

(defun min-of-3 (x y z)
  (if (and (<= x y) (<= x z))
      x
    (min-of-3 y z x)))

の変形として捉えたってことなのかしらん。


CADRでSICP 1.2

| 00:13 | CADRでSICP 1.2 - わだばLisperになる を含むブックマーク はてなブックマーク - CADRでSICP 1.2 - わだばLisperになる

CADRでSICP Exercise 1.2.に挑戦 - Structure and Interpretation of Computer Programs

Exercise 1.2
(5 + 4 + (2 - (3 - (6 + 4/ 5))))/ (3 * (6 - 2) * (2 - 7))
を前置記法で書け。
解答
(// (+ 5 4 (- 2 (- 3 (+ 6 (// 4 5)))))
    (* 3 (- 6 2) (- 2 7)))

//となっているのは、Maclisp〜LISP Machine LISP〜

Zetalispでは、/はエスケープ文字となっているため。

ちなみに(// 4 5)の結果は、0.となる。

2007-04-19

CADRでSICP Exercise 1.1

| 17:57 | CADRでSICP Exercise 1.1 - わだばLisperになる を含むブックマーク はてなブックマーク - CADRでSICP Exercise 1.1 - わだばLisperになる

CADRでSICP Exercise 1.1.に挑戦 - Structure and Interpretation of Computer Programs

今回から1.1から順にSICPの問題に挑戦。

Exercise 1.1
インタプリタに式を入力して結果を観察。
10
-> 10.

(+ 5 3 4)
-> 12.

(- 9 1)
-> 8.

(+ (* 2 4) (- 4 6))
-> 6.

(defvar a 3)
-> NIL

(defvar b (+ a 1))
-> NIL

(= a b)
-> NIL

(if (and (> b a) (< b (* a b)))
    b
  a)
-> 4.

(cond ((= a 4) 6)
      ((= b 4) (+ 6 7 a))
      ('T 25))
-> 16.

(* (cond ((> a b) a)
	 ((< a b) b)
	 ('T -1))
   (+ a 1))
-> 16.

Lisp Machine Lisp固有と思われるところ:

・defvarが値をセットした時にNILを返すところ。

Maclispもそうなのかと思って試してみたら、Maclispは、

変数名を返す。Gaucheでも、SBCLでもそう。この辺は、

言語仕様なのか、処理系依存なのか調べないと分からな

い…けど…まあ…良いか(´▽`*)

2007-04-13

CADRでSICP Exercise 3.1

| 22:38 | CADRでSICP Exercise 3.1 - わだばLisperになる を含むブックマーク はてなブックマーク - CADRでSICP Exercise 3.1 - わだばLisperになる

CADRでSICP Exercise 3.1.に挑戦 - Structure and Interpretation of Computer Programs

挑戦しているL-99も段々問題が難しくなり、また、

Prologの問題をLispで解こうというだけになかなか一筋

縄では行かず、若干煮詰り気味な感じ。

そこで、計算機プログラムの構造と解釈(通称SICP)にも

挑戦してみることに。

一捻りして、LispMで回答を作成することにしてみた。

使用するLispM環境は、CADRのエミュレータ。

1977〜1984位までは、最先端のLisp環境だった模様。

CADRのLispの処理系は、Maclisp系のLisp Machine Lisp

(Zetalispの前身)。

Schemeや、Common Lispと違うところは、レキシカルス

コープではないところ。でも、クロージャを作成する機

構は存在し、Common Lispにかなり近いので、なんとか

なるだろうと。

ということで、今回は、Exercise 3.1に挑戦。次回から

Exercise 1.1から順番に回答を作成予定。

お題:局所状態変数の実現(?)
(define A (make-accumulator) 5)

(A 10)
=> 15

(A 20)
=> 25
を実現するmake-accumulatorを作成せよ。
解答
;; Lisp Machine Lisp
(defun make-accumulator (init)
  (let-closed ((acc init))
    #'(lambda (n)
	(setq acc (+ acc n)))))

;; Scheme
(define (make-accumulator init)
  (let ((acc init))
    (lambda (n)
      (set! acc (+ acc n)))))

面白いところ:

Lisp Machine Lispはダイナミックスコープなので、ク

ロージャを作成するには、それ用の関数等を使うらしい。

主な関数は、そのものずばりな名前のclosure。

let-closedは、マクロで使い勝手的には、Common Lisp

や、Schemeのletと同じ感じ。詳細は、

マニュアル参照

クロージャを操作する関数が色々あり、クロージャの中

身の変数の状態とか覗いてみれたり、変更できたりする。

(setq A (make-accumulator 5.))
(funcall A 10.)
=> 15.

(closure-variables A)
=> acc

(closure-function A)
=> (lambda (n) (setq acc **))

(closure-bindings a)
=> CADRでは未実装?

(closure-alist A)
=> ((acc . 15))

(symeval-in-closure A 'acc)
=> 15

(set-in-closure A 'acc 100.)
=> 100.

(funcall A 10.)
=> 110.

(boundp-in-closure a 'acc)
=> CADRでは未実装?

(locate-in-closure a 'acc)
->#<DTP-LOCATIVE 222343434>

(makeunbound-in-closure a 'acc)
=> CADRでは未実装?

(copy-closure a)
=> CADRでは未実装?