#+title: Sensitive Setq
#+author: screwtape
* Description
We would like to use ==#:trivial-sensitivities== in the way Reichenbacher seems to think
is great. Basically this means replacing eager function evaluation deferment to a queue.
This queue is the list ==*deferred*==. The macro ==(dsetq foo 'bar)== defers assigning
=='bar== to variable ==foo== to the end of ==*deferred*==: It then also nconcs the
==#'find-sensitives== of ==foo== to ==*deferred*==. A list in *deferred* is always
==(foo 'bar)== resulting like (setq foo 'bar), whereas atoms refer to programs to
call with no arguments, so everything operates by side effects, propagating via
==#'dsetq==.
The gist is that in contrast to highly rigid languages and programming systems, a
lisp package can be grown and debugged organically in and as a lisp system.
There's an example at the end of this file of some trivial "pipelining".
I guess worth noting are ==#'advance== which does a number of steps in ==*deferred*==
and ==#'keep-advancing== which is similar to waiting for a new rising_edge.
There's a utility for defining multiple, sensitive signals and signal-setting
processes. It's assumed that a signal (symbol-value 'foo) is set by a
(symbol-function 'foo) after a signal it is sensitive to is resolved from the queue,
the macro ==#'sdefineq==
* Exports
| deferred-setq | 'symbol value &optional pkg |
| dsetq | symbol value |
| *deferred* | list |
| sdefineq | {(name initial-value (&rest sensitivities) lambda)} |
| advance | n-steps |
| keep-advancing | () |
(defun deferred-setq (symbol value &optional (pkg (symbol-package symbol))) "
nconcs ((symbol value)) onto *deferred*
then nconcs (find-sensitives symbol pkg) onto *deferred*
Args: symbol, value &optional (pkg (symbol-package symbol))
do what you might imagine.
"
(setf *deferred*
(nconc *deferred* (list (list symbol value))))
(setf *deferred*
(nconc *deferred* (find-sensitives symbol pkg)))
(values (last *deferred*)))
(defmacro dsetq (name value &rest pkg)
`(deferred-setq ',name ,value ,@pkg))
(defmacro sdefineq (&rest sensitive-defineqs) "
defvars, setfs symbol-function and #'make-sensitive s from
(name initially sensitivities lambda)
Lambda should take no arguments:
It works via deferred side effects and sensitivities (dsetq)
sensitivities is an unquoted list of unquoted symbols
name is similarly unquoted
initially will be evaluated I think
"
`(progn
,@(loop for definition in sensitive-defineqs
for (name initially senss lambda) = definition
collect
`(progn
(defvar ,name ,initially)
(setf (symbol-function ',name) ,lambda)
(apply #'make-sensitive ',name ',senss)))))
(defun advance (n-steps)
(loop repeat n-steps
for item = (pop *deferred*)
when (consp item)
do (execute-deferred-set item)
when (atom item)
do (execute-deferred-funcall item)))
(defun keep-advancing () "
basically get to the next clock tick
" (loop while *deferred*
for len = (length *deferred*)
do (advance len)))
(sdefineq (*a-in* #16(U U U U U U U U U U U U U U U U)
() (lambda ()))
(*a-out* #16(U U U U U U U U U U U U U U U U)
(*b-in*)
(lambda () (dsetq *a-out* *a-in*)))
(*b-in* #16(U U U U U U U U U U U U U U U U)
(*a-in*)
(lambda () (dsetq *b-in* *a-out*)))
(*b-out* #16(U U U U U U U U U U U U U U U U)
(*c-in*)
(lambda () (dsetq *b-out* *b-in*)))
(*c-in* #16(U U U U U U U U U U U U U U U U)
(*b-in*)
(lambda () (dsetq *c-in* *b-out*)))
(*c-out* #16(U U U U U U U U U U U U U U U U)
(*d-in*)
(lambda () (dsetq *c-out* *c-in*)))
(*d-in* #16(U U U U U U U U U U U U U U U U)
(*c-in*)
(lambda () (dsetq *d-in* *c-out*))))
(dolist (in (list #(U U U U U U U U U U U U U U U 1)
#(U U U U U U U U U U U U U U 1 0)
#(U U U U U U U U U U U U U U 1 1)
#(U U U U U U U U U U U U U 1 0 0)
#(U U U U U U U U U U U U U 1 0 1)
#(U U U U U U U U U U U U U 1 1 1)))
(dsetq *a-in* in)
(keep-advancing)
(print "*a-in* ")
(princ *a-in*)
(print "*c-out* ")
(princ *c-out*)
(terpri))
#+end_src
#+RESULTS: smoke
#+begin_example
"*a-in* " #(U U U U U U U U U U U U U U U 1)
"*c-out* " #(U U U U U U U U U U U U 1 1 0 0)
"*a-in* " #(U U U U U U U U U U U U U U 1 0)
"*c-out* " #(U U U U U U U U U U U U 1 1 0 1)
"*a-in* " #(U U U U U U U U U U U U U U 1 1)
"*c-out* " #(U U U U U U U U U U U U U U U 1)
"*a-in* " #(U U U U U U U U U U U U U 1 0 0)
"*c-out* " #(U U U U U U U U U U U U U U 1 0)
"*a-in* " #(U U U U U U U U U U U U U 1 0 1)
"*c-out* " #(U U U U U U U U U U U U U U 1 1)
"*a-in* " #(U U U U U U U U U U U U U 1 1 1)
"*c-out* " #(U U U U U U U U U U U U U 1 0 0)
#+end_example