README.org
January 28, 2022 ยท View on GitHub
#+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
cellform is wrapped into a function and assigned to thecell-functionslot of constructedcellobject (actually, alazy-cell). At any moment,cellwith non-nilcell-functionwill ensure their observed value matches the result of runningcell-function. If you explicitly(setf cell-ref)a cell, itscell-functionis 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
defcellhave 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 likecell-1themselves as symbol macros.There's also
let-cellandlet*-cellthat 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 ofcellwhosecell-insnever 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,
defmodelexpand into adefclass, aninitialize-instancemethod 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, useslot-value.defmodeldoesn'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 ofcomputed-aseverywhere.
-
Documentation Read the source code! There isn't lots of code.