amb評価器の動かし方(DrScheme v4.1対応版)

先日より素人くさいSICP 読書会(http://www.csus4.net/hiki/SICPReading/)におじゃまさせていただいています。
加わったのがだいぶ途中の段階からだったため(問題4.36から)、先ずは話についていくためにきちんとamb 評価器が実行できる環境を手に入れたいと思っていました。
当たり前ですが、動かせる環境が手元にあると理解度がぜんぜん違うんですよね。
今日までに何度か試していたのですが、一見動いているようでいざ演習問題をやろうとするとエラーになったり、訳のわからないハマりどころがあり、役に立っていませんでした。


今日は時間を取っていろいろ試行錯誤し、動かせるところまでで来たので報告してみます。

先ず、amb 評価器のソースを入手し、DrScheme 用に加工

http://mitpress.mit.edu/sicp/code/index.html
から、

  • ch4-ambeval.scm
  • ch4-mceval.scm

を。また、SICPに掲載されているコード断片の詰まった

  • ch4.scm

をダウンロードしてください。

次にch4-ambeval.scm のファイルの先頭に以下を追加して下さい。(入れる場所は適当でいいです)

(define (error message) message)
(define true #t)
(define false #f)

またR5RSでは、eval とapply の定義を上書きできないようになっているようなので(エラーになる)、これらの関数を他の名前に置き換える必要があります。
よってch4-mceval.scm 内のeval とapply をそれぞれmyeval, myapply 等と置換して下さい。
※"eval-何とか" や、"apply-何とか" があるので、盲目的に全部置換しちゃいけません!大丈夫、そんなに数はないから。

ここ、ちょっと面倒ですよね〜。

DrScheme をインストールして起動

起動したら、用意していたch4-ambeval.scm を読み込んでおいて下さい。

言語はR5RS を選択

DrScheme は、ひとつのScheme 実装でなく、いくつかの言語を選択できるようになっています。

以前は"Essentials of Programming Languages(2nd ed.)" を選べば動いたように思いますが、
Version 4.1では"Essentials of Programming Languages(3nd ed.)" になっており、
これでは動かないので別の言語を選択する必要がありました。


ただ、その他の言語をいろいろ試してみたのですが「set-car! が無い」等と怒られてしまいます。
DrScheme の[ヘルプ]-[ヘルプデスク]から、set-car! で検索して確かめると、R5RS に存在していることがわかりました。
よって、R5RSしかないのだと思います。R5RS を選んでください。


(R5RSでもうまく動かなかった部分は泥臭く調整しましたが、それが上に述べたファイルの改変の内容でした。)

DrScheme の実行ボタンを押す

ようこそ DrScheme, バージョン 4.1 [3m].
言語: R5RS; memory limit: 128 megabytes.
metacircular-evaluator-loaded
amb-evaluator-loaded

のように表示されればOK.

そして以下を打ち込んで実行し、手動でamb 評価器を起動します。

;; この2ステップでamb 評価器が起動
(define the-global-environment (setup-environment))
(driver-loop)

この段階でamb 評価器が起動しています。
続いて以下のコードを試してみてください。

;; amb 評価器内で実行
(define (require p) (if (not p) (amb)))
(define (an-element-of items) (require (not (null? items))) (amb (car items) (an-element-of (cdr items))))
(an-element-of '(1 2 3))

結果として1が表示されれば動いています。

更なる動作確認のため、SECTION 4.3.2 -- Logic Puzzles も動かしてみましょう。

ch4.scm から関数require、distinct? およびmultiple-dwelling をamb 評価機内にコピペして、
その上で(multiple-dwelling) とすると実行が確認できます。

具体的には以下のようなコマンド行になるでしょう。

;;; Amb-Eval input:
(define (require p)
  (if (not p) (amb)))

(define (distinct? items)
  (cond ((null? items) true)
        ((null? (cdr items)) true)
        ((member (car items) (cdr items)) false)
        (else (distinct? (cdr items)))))

(define (multiple-dwelling)
  (let ((baker (amb 1 2 3 4 5))
        (cooper (amb 1 2 3 4 5))
        (fletcher (amb 1 2 3 4 5))
        (miller (amb 1 2 3 4 5))
        (smith (amb 1 2 3 4 5)))
    (require
     (distinct? (list baker cooper fletcher miller smith)))
    (require (not (= baker 5)))
    (require (not (= cooper 1)))
    (require (not (= fletcher 5)))
    (require (not (= fletcher 1)))
    (require (> miller cooper))
    (require (not (= (abs (- smith fletcher)) 1)))
    (require (not (= (abs (- fletcher cooper)) 1)))
    (list (list 'baker baker)
          (list 'cooper cooper)
          (list 'fletcher fletcher)
          (list 'miller miller)
          (list 'smith smith))))

;;; Starting a new problem
;;; Amb-Eval value:
ok

;;; Amb-Eval input:

;;; Starting a new problem
;;; Amb-Eval value:
ok

;;; Amb-Eval input:
(multiple-dwelling)		;; ここで実行

;;; Starting a new problem
;;; Amb-Eval value:
((baker 3) (cooper 2) (fletcher 4) (miller 5) (smith 1))

SICPにある通りの答えが出ていますので、きちんと動いていますね。

amb評価器を止める

amb評価器はScheme のアプリケーションにすぎないので、右上の[停止◎] を押せばいいです。


こんな感じで動かせるようになります。
あ〜しんどかった。