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 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

  • Documentation Read the source code! There isn't lots of code.