回路シミュレータ完成
おおげさだが、SICP の回路シミュレータが common lisp で動くようになった。SICP にあった reset はあえて入れていない。full-addr まで動いた。
さて、LoL の defmacro! 使いどころが難しい。LoL でも必要のないところは defmacro (!がない普通の defmacro) を使っている。例えば
(defmacro def-signal (var) `(if (fboundp (quote ,var)) (error (format nil "var is already defined ~s" ,var)) (setf (symbol-function (quote ,var)) (alet ((signal-value) (action-procedures)) .... プログラムは続く ,var はでてこない。
この場合 alet の signal-value や action-procedures は g! の必要がない。というのも ,var がその後出てこないから。一方、マクロの変数が let をまたぐようなケースでは g! がひつようになる。ややこしい。
あと probe ではちゃんと name を let で補足してやらないと defmacro でかいたら単にマクロ展開になってしまう。シンボルならそれでもいいのだが、シンボルの入った変数だと変数の内容が変わってしまうと変数の中身が変わったら表示も変わってしまう。map などで一気に probe を使う時に都合が悪い。今書いていて o! を使えばいいときがついた。
tlist は最初使い方が良くわからず、かならず update したり、FILO としてしかつかっていなかったが、update は自動的に行われる、入れ方を正しくすれば FIFO にも FILO にもなることがわかった。ソースをちゃんと読もう。
シミュレーション結果は次の通り
0: S0 ==> NIL 0: CO0 ==> NIL 16: CO0 ==> 1 16: S0 ==> 0 16: S0 ==> 1
同時刻に S0 がばたついている。実際の回路もそうだろう。しかし結果がみにくい。回避方法としては表示時あるいは action 時に同時刻のものは最後だけが有効とする。シミュレーションをより効率的に行うとすれば、ばたついている情報が伝播してしまうと効率悪いので、同時刻の同じアウトプットに対するアクションは最後のものだけを有効にする必要がある。アクションによるアクションの追加にもうまく対応しないと遅延ゼロでのシミュレーションが破綻しそうだ。