インバータしか作っていないけど、こういうの作っていて楽しいね。
;; SICP Circuit simulator ;;---------------------------------------- ;; queue (defun make-queue () (cons '() '())) (defun front-ptr (queue) (car queue)) (defun rear-ptr (queue) (cdr queue)) (defun set-front-ptr! (queue item) (rplaca queue item)) (defun set-rear-ptr! (queue item) (rplacd queue item)) (defun empty-queue? (queue) (null (front-ptr queue))) (defun front-queue (queue) (if (empty-queue? queue) (error "FRONT called with an empty queue ~a" queue) (car (front-ptr queue)))) (defun insert-queue! (queue item) (let ((new-pair (cons item '()))) (cond ((empty-queue? queue) (set-front-ptr! queue new-pair) (set-rear-ptr! queue new-pair) queue) (t (rplacd (rear-ptr queue) new-pair) (set-rear-ptr! queue new-pair) queue)))) (defun delete-queue! (queue) (cond ((empty-queue? queue) (error "DELETE! called with an empty queue ~a" queue)) (t (set-front-ptr! queue (cdr (front-ptr queue))) queue))) ;;---------------------------------------- ;; time segment (defun make-time-segment (time queue) (cons time queue)) (defun segment-time (segment) (car segment)) (defun segment-queue (segment) (cdr segment)) ;;---------------------------------------- ;; agenda (defun make-agenda () (list 0)) (defun current-time (agenda) (car agenda)) (defun set-current-time! (agenda time) (rplaca agenda time)) (defun segments (agenda) (cdr agenda)) (defun set-segments! (agenda segments) (rplacd agenda segments)) (defun first-segment (agenda) (car (segments agenda))) (defun rest-segment (agenda) (cdr (segments agenda))) (defun empty-agenda? (agenda) (null (segments agenda))) (defun add-to-agenda! (time action agenda) (labels ((belongs-before? (segments) (or (null segments) (< time (segment-time (car segments))))) (make-new-time-segment (time action) (let ((queue (make-queue))) (insert-queue! queue action) (make-time-segment time queue))) (add-to-segments! (segments) (if (= time (segment-time (car segments))) (insert-queue! (segment-queue (car segments)) action) (let ((rest (cdr segments))) (if (belongs-before? rest) (rplacd segments (cons (make-new-time-segment time action) rest)) (add-to-segments! rest)))))) (let ((segments (segments agenda))) (if (belongs-before? segments) (set-segments! agenda (cons (make-new-time-segment time action) segments)) (add-to-segments! segments))))) (defun remove-first-agenda-item! (agenda) (let ((q (segment-queue (first-segment agenda)))) (delete-queue! q) (if (empty-queue? q) (set-segments! agenda (rest-segment agenda))))) (defun first-agenda-item (agenda) (if (empty-agenda? agenda) (error "Agenda is empty -- FIRST-AGENDA-ITEM") (let ((segment (first-segment agenda))) (set-current-time! agenda (segment-time segment)) (front-queue (segment-queue segment))))) ;;---------------------------------------- ;; simulator (defvar *agenda* nil) (setf *agenda* (make-agenda)) (defun after-delay (delay action) (add-to-agenda! (+ delay (current-time *agenda*)) action *agenda*)) (defun propagate () (if (empty-agenda? *agenda*) 'done (let ((first-item (first-agenda-item *agenda*))) (funcall first-item) (remove-first-agenda-item! *agenda*) (propagate)))) (defun call-each (procs) (if (null procs) 'done (progn (funcall (car procs)) (call-each (cdr procs))))) (defun make-wire () (let ((signal-value 0) (action-procs '())) (labels ((set-signal! (value) (if (= value signal-value) 'done (progn (setf signal-value value) (call-each action-procs)))) (add-action! (proc) (setf action-procs (cons proc action-procs)) (funcall proc)) (dispatch (method) (case method ('get-signal signal-value) ('set-signal! #'set-signal!) ('add-action! #'add-action!) (t (error "Unknown operation ~a -- WIRE" method))))) #'dispatch))) (defun get-signal (wire) (funcall wire 'get-signal)) (defun set-signal! (wire value) (funcall (funcall wire 'set-signal!) value)) (defun add-action! (wire proc) (funcall (funcall wire 'add-action!) proc)) (defun logical-not (value) (cond ((= value 0) 1) ((= value 1) 0) (t (error "Invalid signal ~a" value)))) (defvar *inverter-delay* 2) (defun inverter (input output) (add-action! input #'(lambda () (let ((new-value (logical-not (get-signal input)))) (after-delay *inverter-delay* #'(lambda () (set-signal! output new-value)))))) 'ok) (defun probe (name wire) (add-action! wire #'(lambda () (format t "~a ~a ~a~%" (current-time *agenda*) name (get-signal wire))))) ;;---------------------------------------- ;; circuit (defparameter w1 (make-wire)) (defparameter w2 (make-wire)) (inverter w1 w2) (probe "w1" w1) (probe "w2" w2)
動かしてみる。
0 w1 0 0 w2 0 CL-USER> (propagate) 2 w2 1 DONE CL-USER> (set-signal! w1 1) 2 w1 1 DONE CL-USER> (propagate) 4 w2 0 DONE CL-USER>
もう少しいろいろ遊びたいところだけど、先に進もう。
0 件のコメント:
コメントを投稿