alet もつかう
(defmacro make-wire (var) `(if (fboundp (quote ,var)) (princ "error!!!") (setf (symbol-function (quote ,var)) (alet ((signal-value) (action-procedures)) (dlambda (:get-signal () signal-value) (:set-signal (new-value) (if (not (eq signal-value new-value)) (prog1 (setf signal-value new-value) (mapcar (lambda (proc) (funcall proc this)) action-procedures)) 'done)) (:add-action (proc) (setf action-procedures (cons proc action-procedures)) (funcall proc this)))))))
LoL にどっぷりはまっているな、、、エラーの書き方がいまいち。
VHDL とかだど X とか Z という状態がある。これをどう表現したものか。component とか process や signal の vector 化にも対応したいな、、、make-wire ではなく make-signal か。固定小数点も扱えるようにしたい。
さてコーディング中に
(defmacro inverter-gate (input output) `(let ((sym-input (symbol-function (quote ,input))) (sym-output (symbol-function (quote ,output)))) (funcall sym-input :add-action
というくだりが何回も出てくるようになった。いままで C++ のプログラミングのときは”こういうのはコピーで作る”が当たり前で(もちろん程度問題。基本的にはコピーでプログラム作っちゃだめよ)メタプログラムをするとソースの可読性が下がるのでやめていた。
Smalltalk/objective-C/C++/Java でオブジェクト指向を学んだ私なりの結論はオブジェクト指向はソースの再利用性には寄与しない。単純な卵プログラムをもっておきそれをコピーして各プロジェクトに適用する。プロジェクトで同じ問題を抱えるかもしれない。可能であれば卵プログラムにその問題の解決を反映できるかもしれないが、基本的には問題は各プロジェクトで個別に対応。コピーという作戦なので CVS や SVN などのソース管理ソフトは必須。卵プログラムをいくつ持っているかがその人の経験の幅だ。
というのが10年以上も前の結論。そして、今思うと、卵プログラムが”メタプログラム”であれば再利用性を高めることが出来るが C++ ではそれは複雑すぎるのでやらない。基本的にはコピー。しかし、メタプログラムが当たり前に出来ればより再利用性を高めることが出来るかもしれない。ただ、実用レベルになるとどうしても製品の個別対応はひつようなので最終的にどこかで、元のプログラムとは分離する必要があると思う。
で、上のくだりが何回も出てくるので、LoL に習い、flatten でフラットにして s! などのキーワードのシンボルを探し、それを自動的に symbol-function でシンボルにしてくれるようなマクロがかけるような気がするし、だめなような気もするぞ。(どっちだよ?)
やばいよね。いずれにせよ同じパターンがでてきたらメタプログラムで集約することを考えるようになった。やばいよね。なにがやばいって、lisp にどっぷりはまりそうで。
うまくいけば inverter-gate と and-gate の違いは入力と、中の関数だけだから、
(defmacro!! inverter-gate (s!input s!output) (make-gate (s!input) (s!output) #'logical-not)) (defmacro!! and-gate (s!input0 s!input1 s!output) (make-gate (s!input0 s!input1) (s!output) #'logical-and))
だけになる。どんどんブラックボックス化していくぞ。これがブロックを積み上げるの意味か、、、数学的な快感はあるが、本当にこれでいいのかなぁ。R&D的にはよいに違いない。