(We eventually just get the above visualisations working as easy as pasting or typing whatever trees as nested lists. It is available as a common lisp asdf package inside my screwlisps-knowledge
system git repository) (My example is intentionally similar to Lispworksā one here).
Using jackdanielās McCLIM implementation of the CLIM 2 spec. A foundational principle of lisp was that the code of lisp, s-expressions, be a sequence type used by the programming language. Of lispās sequences, (lists were chosen instead of #(vectors for example))
. While it is (unambiguous and much cleaner to write a list like this)
, the listās truest form is as nested cons
pairs (like . (this . ((for . (one . nil)) . (example . nil))))
. The terminating dot-nil
s make lists true-lists. Doug Merritt says it is basically a regret that non-true-lists are allowed, e.g. (a . b)
though this useage remains popular basically when we want to use cons
es as pairs per se instead of as building blocks for true lists.
For these kinds of reasons, the common lisp interface manager spec actually includes visualizing these cons
trees fairly directly.
I am assuming you are using sbcl, McCLIM, eev and emacs [] or understand your differences thereto.
My common lisp asdf
package is going ]in my screwlisps-knowledge repo](https://codeberg.org/tfw/screwlisps-knowledge).
(eepitch-shell)
mkdir -p ~/common-lisp/
cd ~/common-lisp
git clone https://codeberg.org/tfw/screwlisps-knowledge.git
cd
#|
(eepitch-sbcl)
|#
(asdf:load-system :mcclim)
#p"screwlisps-knowledge/cons-grapher.lisp"
(uiop:define-package :screwlisps-knowledge/cons-grapher
(:mix :series :clim :clim-lisp :cl)
(:export #:graph-frame
#:graph
#:define-graph-frame-command
#:visualize))
(in-package :screwlisps-knowledge/cons-grapher)
(define-application-frame graph-frame
()
((graph :initarg :graph
:accessor graph))
(:pane :application
:display-function 'display-graph
:incremental-redisplay t)
(:default-initargs :graph '((this (could) (be)) (your (graph) (this)))))
(defmethod display-graph ((f graph-frame) p)
(updating-output (p)
(format-graph-from-roots
(graph f)
#'(lambda (x s) (princ (car x) s))
#'cdr
:orientation :vertical
:merge-duplicates t
:duplicate-key #'car)))
The default update behaviour is to update the application-frame
graphics when a command
happens, so we should use command
s.
(define-graph-frame-command (com-set-graph :menu nil :name t)
((expression expression))
(setf (graph *application-frame*) expression))
(define-graph-frame-command (com-graph :menu t :name t)
()
(let ((frame *application-frame*))
(accepting-values ()
(let ((expressions
(accept '(sequence expression))))
(print expressions *terminal-io*)
(execute-frame-command frame `(com-set-graph ,(car expressions)))))))
(defun visualize
(&rest cons-tree)
(let ((grapher (make-application-frame 'graph-frame)))
(when cons-tree
(execute-frame-command grapher
`(com-set-graph ,cons-tree)))
(run-frame-top-level grapher)))
(asdf:load-system :mcclim)
(in-package :clim-user)
(asdf:load-system :screwlisps-knowledge/cons-grapher)
(use-package :screwlisps-knowledge/cons-grapher)
(remember, autocomplete in common lisp emacs with slime is M-/
)
(visualize '(a (b) (c)) '(d (e (c))))
If we want access to the application frame being used, for example to open and close the same one at different times, we can directly make-application-frame
it.
(make-application-frame 'graph-frame :graph '((a (b (c))) (x (y (z) (c)))))
A small amount of window dressing around the CLIM 2 specās format-graph-from-roots
so we just re/write in cons trees and get graphs of them. I get a lot of mileage out of it. Three uses I have planned are
I think these are better represented as cons tree graphs of atoms than struct
s or class
es because html elements are basically structural - they are their element name appearing in their html, along with a a property list, which symbol atoms already have. All html elements more or less always can have children which are a sequence of strings and more html trees. Encoding what html happens to have been defined like is not my intent here; however, it seems coincident with these cons trees, and this is a way of easily looking with those. I note that you can paste into that application-frameās accepting-values easily.
I note that my accepting-values
clearly should instead be (accepting-values (t :own-window t) <body>)
because McCLIM makes odd compromises to squeeze it onto that one frame sometimes.
See you on the thread for this article on the Mastodon.
This classic lisp tree visualization useage has been part of lisp useage for a long time. To lose it decontextualises lisp in a harmful [sic] way. Common lisp interface manager was the heir to Lisp machine dynamic-windows (pers. coms.). Cons tree graphs loosely in this style go back much, much further into lispās approximately hundred year history. In particular, modernly, McCLIM was started by Robert Strandh in 1996 and then joyfully offloaded, eventually to jackdaniel.
For this kind of reason, please do share this bit to newcomers to the lisp community so they are not confused into thinking using graphs in program and data structure design and exploration was invented by low quality fly-by-night in-and-out financial ventures. You have my blessing to share it whereever and however occurs to you.
OR BETTER if you have something to say, say it on the Mastodon, come on an episode of the lispy gopher climate like Vassil and Kent do.
screwlisp proposes kittens