dlambda meets SICP

SICP のディジタル回路のシミュレータってのを common lisp 上にポーティングしようと試みている。まずは make-wire からだ。LoL を読んだ直後だったので dlambda が使えると直感的に思い試して見る。

 (let ((signal-value)
                 (action-procedures))
             (dlambda
               (:get-signal () signal-value)
               (:set-signal (new-value)
                            (if (not (eq signal-value new-value))
                              (progn (setf signal-value new-value)
                                     (call-each action-procedures))
                              'done))
               (:add-action (proc)
                            (setf action-procedures (cons proc action-procedures))
                            (proc))))

参考までに書くと(誰の参考にもならないだろうが)私の環境は FreeBSD + vi + clisp で、vi で編集して ctrl-z で中断して clisp を起動して実行し ctrl-z で中断して、、、というなかなかオールドスタイル。そこまでするなら screen で切り替えろという気もする。

さて、上の式は簡単に出来た。setf と symbol-function で簡単に名前も付けられた。これを簡便にするには、、、、最初のアイデアが関数で返すことだったのだが、scheme のように define で関数を定義できない。scheme は関数と変数の区別が無いのでそういうことができるのだが、common lisp は出来ない。その代わりといったらなんだがマクロがある。

(defmacro make-wire (var)
     (setf (symbol-function (quote ,var))
... let による関数定義が続く

これはすごい。scheme では関数と変数が同じなので make-wire も
(define a (make-wire))
だ。これはscheme として不自然ではない。そしてこれは scheme という枠組みの延長にある。しかし、common lisp で上のマクロを使うと (make-wire a) だ。完全に lisp の中に溶け込んで新しい構文を提供している。一体全体どういうことなのだろう?
C で言えば

my_if (a < b < c) {
} my_else {
}

みたいな新たな構文が定義できるような感じだ。C++ ではオペレータの over write により C++ の構文拡張が出来るがそれの上を行く。上じゃないかもしれないけど、次元が違うことは確か。C++ で define やら template を屈指して(とあるプログラムを)書くと

//------------------------------------------------------------------------
CXXR_BEGIN {
        CXXR(A, A)
        CXXR(A, D)
        CXXR(D, A)
        CXXR(D, D)
} CXXR_END

CXXXR_BEGIN {
        CXXXR(A, A, A)
        CXXXR(A, A, D)
        CXXXR(A, D, A)
        CXXXR(A, D, D)
        CXXXR(D, A, A)
        CXXXR(D, A, D)
        CXXXR(D, D, A)
        CXXXR(D, D, D)
} CXXXR_END

と書いたことがあるが、もはや C++ じゃない。lisp は言語拡張できて、それでいてまだ lisp だ。逆に言うとそれだけ原始的といえるかもしれない。与えられた自由度が大きすぎるので使う人を選ぶ。誰もが猛獣使いにはなれないということだ。