新千葉 ガーベージ・コレクション

FPGA マガジンやインターフェースで書けなかったこと等をちょぼちょぼ書いてます。@ryos36

[SICP] apply

primitive か compound かを見て処理をする。

(defun scheme-apply (procedure arguments)
  (cond ((primitive-procedure? procedure)
         (apply-primitive-procedure procedure arguments))
        ((compound-procedure? procedure)
         (scheme-eval-sequence
           (procedure-body procedure)
           (extend-environment
             (procedure-parameters procedure)
             arguments
             (procedure-environment procedure))))
        (t
          (scheme-error
            "Unknown procedure type -- APPLY" procedure))))

apply が終わるとだいたいできあがり。
まだ完成じゃないけどここにおいておこう。
http://echoesi.sinby.com:8087/ja/tech/careless-lisper/sicp/

遅延評価

こんなかんじ?だいたいできた。

(defun force-it (obj)
  (cond ((thunk? obj)
         (let ((result (actual-value (thunk-exp obj) (thunk-env obj))))
           (setf (car obj) 'evaluated-thunk)
           (setf (cadr obj) result)
           (setf (caddr obj) nil)
           result))
        ((evaluated-thunk? obj) (thunk-value obj))
        (t obj)))

amb

これは prolog だからとばす。まぁもどってきてやってもいいけど。あのころはビル・ゲイツでさえも、AI と prolog に期待感を持っていたんだよね。

積極制御評価器

原文では "The Explicit-Control Evaluator"。原文もわかりづらい。1990 年ごろ?だから許そう。いまなら Virtual Machine だろう。以前、chromeJavaScript が早いという話を聞いてソースを読んだことがある。結局、VM を作っていた。VM もかなり範囲が広いので一概には言えない。ここでいう"The Explicit-Control Evaluator"は Java VM のようなものではない。もっと高いレベルの演算を期待している。というか、ほとんどインタプリタ。何を導入したかったのかというと、どうやら goto を導入したかったようなのだ。
結局、lisp でも C でもその関数のレベルで scheme を使ってしまうと、どうしても、末尾再帰ができない。だから goto を導入したい。また、goto が導入されれば、Call/CC が出来る。Call/CC って Ada のランデブー(rendez vous)では?実は使いようが一杯あると思っている。特に GUI
SICP では scheme の上で全てを実行しているので関数の定義をしてそれを変数に bind して、簡単に実行できる。しかし、common lisp ではそうはいかない。funcall を使う必要がある。
例えばこんな感じ。まぁ元を尊重して funcall でつくるかな。いじるとわからなくなるし。

(defun test-make-new-machine ()
  (let ((var 0))
    (labels ((get-var ()
                      var)
             (plus ()
                   (setf var (+ 1 var)))
             (dispatch (msg)
                       (cond ((eq msg :get-var) #'get-var)
                             ((eq msg :plus) #'plus)
                             (t (format t "error!")))))
      #'dispatch)))

(setf machine (test-make-new-machine))

(let ((*debug-flag* t))
  (do-test-case
    (labels ((fde (ee) (format t "~a~%" ee)))
      (fde (funcall machine :get-var))
      (fde (funcall (funcall machine :get-var)))
      (fde (funcall (funcall machine :plus)))
      (fde (funcall (funcall machine :get-var)))
                    )))

こうすれば funcall が一つ減るか、、、

(setf (symbol-function 'machine) (test-make-new-machine))

個人的には clos を使うか、LoL の dlamda をつかえばもっとスマートになるという気がしている。しかしそうすると SICP からどんどん離れるな、、、