https://github.com/kchanqvq/lwcells
Light Weight Cells
https://github.com/kchanqvq/lwcells
Last synced: about 1 month ago
JSON representation
Light Weight Cells
- Host: GitHub
- URL: https://github.com/kchanqvq/lwcells
- Owner: kchanqvq
- Created: 2022-01-10T03:37:01.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2024-10-06T03:06:50.000Z (over 1 year ago)
- Last Synced: 2025-03-05T19:50:14.474Z (about 1 year ago)
- Language: Common Lisp
- Size: 46.9 KB
- Stars: 18
- Watchers: 4
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.org
Awesome Lists containing this project
- awesome-cl - lwcells - Light Weight Cells. (Miscellaneous ##)
README
#+TITLE:LWCELLS - Light Weight Cells
~LWCELLS~ is a dataflow extension to Common Lisp. It maintains a
consistent state of cells according to functions specifying their
relation. ~LWCELLS~ is designed to be simple, clean, compositional
and flexible.
* Tutorial
Basic usage:
#+BEGIN_SRC lisp
(use-package :lwcells)
(defparameter *cell-1* (cell 1))
(defparameter *cell-2* (cell 2))
(defparameter *cell-3* (cell (+ (cell-ref *cell-1*) (cell-ref *cell-2*))))
(cell-ref *cell-3*) ; => 3
(setf (cell-ref *cell-2*) 5)
(cell-ref *cell-3*) ; => 6
#+END_SRC
*Hackers' note:* The body of each ~cell~ form is wrapped into a
function and assigned to the ~cell-function~ slot of constructed
~cell~ object (actually, a ~lazy-cell~). At any moment, ~cell~ with
non-nil ~cell-function~ will ensure their observed value matches the
result of running ~cell-function~. If you explicitly ~(setf
cell-ref)~ a cell, its ~cell-function~ is removed to prevent it from
running again and overwrite the explicitly assigned value.
Fancier syntax sugar that does roughly the same thing as above:
#+BEGIN_SRC lisp
(defcell *cell-1* 1)
(defcell *cell-2* 2)
(defcell *cell-3* (+ *cell-1* *cell-2*))
#+END_SRC
~defcell~ have the additional nicety that when you redefine a cell,
if an existing cell object is to be overwritten, such cell is also
deactivated so that observers (to be explained!) defined on the old
cell stop making noises.
*Hackers' note:* Under the hood, this stores the cell objects in
variable like ~*cell-1*-cell~, and defines symbols like ~*cell-1*~
themselves as symbol macros.
There's also ~let-cell~ and ~let*-cell~ that does the similiar for
lexical variables.
Observers:
#+BEGIN_SRC lisp
(defcell *cell-1* 1)
(defcell *cell-2* 2)
(defcell *cell-3* (+ *cell-1* *cell-2*))
(defun report-assign (cell)
(let ((*print-circle* t))
(format t "Assigning ~a to ~a." (cell-ref cell) cell)))
(add-observer *cell-3*-cell 'report-assign)
(setf *cell-2* 4)
;; => Assigning 5 to #1=#S(CELL ...)
#+END_SRC
*Hackers' note:* Under the hood, observers are implemented as ~observer-cell~,
a special kind of ~cell~ whose ~cell-ins~ never change.
Convenience for CLOS:
#+BEGIN_SRC lisp
(defmodel item () ((weight :cell 0 :initarg :weight)))
(defmodel container ()
((items :cell nil)
(weight :cell (reduce #'+ (items self) :key #'weight))))
(defvar *container* (make-instance 'container))
(weight *container*) ; => 0
(push (make-instance 'item :weight 10) (items *container*))
(weight *container*) ; => 10
#+END_SRC
*Hackers' note:* Under the hood, ~defmodel~ expand into a
~defclass~, an ~initialize-instance~ method to store cell objects
into slots, and some accessors method to read/write values from cell
objects in the slots. You can then use the accessors method to
transparently access reactive values. To get and manipulate the
underlying cell objects, use ~slot-value~.
~defmodel~ doesn't use any MOP magic, and is fully compatible with
standard CLOS classes.
* Related works
- [[https://github.com/kennytilton/cells][cells]] :: This is very
powerful, but also very complicated. AFAIU cells are also always
attached to slots and don't exist on their own. I might be
wrong -- I don't understand all the code!
- [[https://github.com/hu-dwim/hu.dwim.computed-class][computed-class]] ::
A bit more complicated than ~lwcells~. The syntax is also a bit less
sweet, requiring lots of ~computed-as~ everywhere.
* Documentation
Read the source code! There isn't lots of code.