--- layout: ../Site.layout.js --- # Screwlisps-knowledge Common lisp interface manager spec Cons Tree Graphics - «.setup» (to "setup") - «.source» (to "source") - - «.define package» (to "define package") - - «.define frame» (to "define frame") - - «.display function» (to "display function") - - «.frame commands» (to "frame commands") - «.visualize eg» (to "visualize eg") - «.useage» (to "useage") - - «.headless useage» (to "headless useage") - - - «.interactive new cons trees» (to "interactive new cons trees") - - «.directly make the frame» (to "directly make the frame") - «.conclusion» (to "conclusion") - «.fin» (to "fin") (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](https://codeberg.org/tfw/screwlisps-knowledge)) (My example is intentionally similar to [Lispworks' one here](https://www.lispworks.com/documentation/lwu41/climuser/GUID_286.HTM#HEADING286-0)). Using [jackdaniel](https://turtleware.eu)'s [*McCLIM*](https://codeberg.org/McCLIM/McCLIM) implementation of [the CLIM 2 spec](http://bauhh.dyndns.org:8000/clim-spec/index.html). A foundational principle of lisp was that the code of lisp, *s-expression*s, 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-list*s. 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](http://bauhh.dyndns.org:8000/clim-spec/index.html) actually includes visualizing these `cons` trees fairly directly. # Setup - «setup» (to ".setup") I am assuming you are using [sbcl](https://sbcl.org), [McCLIM](https://codeberg.org/McCLIM/McCLIM), [eev](https://anggtwu.net/eev-intros/find-escripts-intro.html) and emacs [] or understand your differences thereto. My common lisp [`asdf`](https://github.com/fare/asdf/blob/master/doc/best_practices.md) 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) ``` # Source of `#p"screwlisps-knowledge/cons-grapher.lisp"` - «source» (to ".source") ## Define and go into the package - - «define package» (to ".define package") ``` (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 the frame - - «define frame» (to ".define frame") ``` (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))))) ``` ## The display function for our application frame. - - «display function» (to ".display function") ``` (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))) ``` ## Commands for setting and querying the user for cons trees - - «frame commands» (to ".frame commands") 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))))))) ``` # A function that just pops a frame up showing a cons tree - «visualize eg» (to ".visualize eg") ``` (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))) ``` # Useage - «useage» (to ".useage") ``` (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-/`) ## Headless - visualize - - «headless useage» (to ".headless useage") ``` (visualize '(a (b) (c)) '(d (e (c)))) ``` ### Interactively writing in new cons trees - - - «interactive new cons trees» (to ".interactive new cons trees") ## Directly making the frame - - «directly make the frame» (to ".directly make the frame") 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))))) ``` # Conclusion - «conclusion» (to ".conclusion") 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 1. Working with [Kitten html components](https://kitten.small-web.org/tutorials/components-and-fragments/) as *structural types* 1. [*Cross referenced editor facility*](/show/Kent-M-Pitmans-Whither-Original-Thought/) style tagging of these blog articles 1. Intent-based tours of these blog articles. 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) )` because McCLIM makes odd compromises to squeeze it onto that one frame sometimes. # Fin - «fin» (to ".fin") See you on [the thread for this article on the Mastodon](https://gamerplus.org/@screwlisp/114679554933243320). 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](https://github.com/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](https://gamerplus.org/@screwlisp/114679554933243320), come on [an episode of the lispy gopher climate like Vassil and Kent do](/show/Vassil-Nikolov-Kent-Pitman-assertables-compilation-declare).