Presentation-type programming
1. Itching for days
My pre-recorded episode on https://anonradio.net today was about the presentation concept of types in common lisp (interface manager).
I got a bit muddled trying to jam during the show, so here's everything in slow motion hashed out after for you.
If you need to start lisp as a beginner, read an article like my friend Andrew Kravchuk's. I kinda assume you can start lisp. I get that it's hard for people from other languages.
Lisp happens interactively. Again, read Andrew.
This is the digest version of how I (automatically) started lisp:
1.1. starting lisp for emacs for this article
1.1.1. Run ecl shell
ecl
1.1.2. Load asdf and mcclim lisp
(require "asdf") (asdf:load-system :mcclim)
1.1.3. Start swank for emacs' use lisp
(load #p"~/.emacs.d/slime/start-swank.lisp")
1.1.4. Connect to that swank server (defaults) elisp
(slime-connect "localhost" 4005)
1.1.5. Good work getting to here ;p you are now an expert
Onwards to making the type theory people weep tears and gnash teeth!
2. Presentation types and us
2.1. Go into clim-user lisp clim
(in-package :clim-user)
User packages are made to absorb package users' (your) creations. The gist is that exported symbols of the package you're using are mixed to become internal symbols of the -user package, so you can use it as intended but not accidentally break anything.
2.2. Make an output history lisp clim
(defvar *tree-san* (make-instance 'standard-tree-output-history))
CLIM's central concept is updating panes by replaying its mutable output history. This is the bit we want to claw at.
2.3. Make an interactor pane lisp clim
By the way, we're using these naked as just in-memory streams without trying to draw them. We could graft it into a frame where it hooks up with machinery to paint itself, but here now I am specifically not doing that. We've got to get its vibration.
(defvar *inter* (make-instance 'interactor-pane :output-record *tree-san*))
While there are no restraints on using either for either, interactor-panes are informally identified with standard-input and application-panes with standard-output, so let's just use them as though they're like that.
2.4. Make an application pane lisp clim
(defvar *appli* (make-instance 'application-pane :output-record *tree-san*))
Now we have two panes (in-memory streams in some sense) that we are kinda pretending are a front and back.
2.5. Present something! lisp clim
Remember present is like a type-aware advancement of print.
(present '("foo" "bar") '(sequence string) :stream *inter*)
2.6. Present it by shadowing the default stream lisp clim
(let ((*standard-output* *inter*)) (present '("foo" "bar")))
Clim tries to guess the presentation type we want if we don't tell it, and we lexically shadowed the default stream (standard-output) with our inter.
Oh, interesting. It guessed (sequence t) instead of (sequence string). (t is a catch-all presentation-type).
2.7. What ever happened to tree-san lisp clim
Remembering (I forgot in the show) that we are using appli as our output
(map-over-output-records
(lambda (x)
(terpri)
(present (presentation-object x)
(presentation-type x)))
(stream-output-history *appli*))
So the leaves are of presentation-type (and CLOS class) PRESENTATION, which carries an object, being the data and a presentation-type, being how the data was presented to it. I don't know if you had one of those scarves that could be worn as a scarf or as a hat as a child, but the presentation-type carries the extra information that the scarf is being used as a hat, which is absent from simply saying you have a scarf. Of course it could be reconfigured to being a hat. Making reconfigurability intrinsic is an interesting and non-trivial innovation I attribute to clim. I'm looking forward to hearing from you, type theorists.
2.8. Defining tree branch presentation-type lisp Clim
Here, I choked a bit during the show. Sorry dinner was late.
(define-presentation-type tree-presentation () :inherit-from '(presentation))
It's really convenient to derive from an existing presentation-type. Here I tried to get a new standard-tree-output-record into its children by presenting one to it, but I ended up with a presentation whose data was the output record rather than just the output record, which flummoxed me. So we'll define its presentation-type
2.9. presentation-typep
We have to be able to distinguish members of this type!
(define-presentation-method presentation-typep :around (object (type tree-presentation)) (and (call-next-method) (typep (presentation-object object) 'output-record)))
My tree-presentation satisfies however the presentation presentation-type is established with call-next-method, and adds the requirement that its presentation-object is suitable for map-over-output-records (ie is a node).
After some thought, I generalised standard-tree-output-record to just be output-record, since it could also be a standard-sequence-output-record.
2.10. Traverse, somehow
(defvar *traversal-indent* 0) (defvar *traversal-spacing* 4) (defun traverse (output-record) (map-over-output-records (lambda (x) (terpri) (format t "~@,,v,' a" *traversal-indent* #\{) (cond ((presentation-typep x 'tree-presentation) (incf *traversal-indent* *traversal-spacing*) (traverse (presentation-object x)) (decf *traversal-indent* *traversal-spacing*)) ((presentation-typep x 'presentation) (present (presentation-object x) (presentation-type x)))) (princ "}")) output-record))
It's a bit annoying that there isn't a presentation-typecase macro by clim, though perhaps this is meant to be done by type specifiers on present in the first place.
2.10.1. set up a nested tree-output
Let's just make a different output-history for a different pane
(defvar *branch* (make-instance 'standard-tree-output-history)) (defvar *branch-pane* (make-instance 'interactor-pane :output-record *branch*)) (present "Beeblebrox" 'string :stream *branch-pane*) (let ((*standard-output* *inter*)) (present *branch*))
I guess deeper would be more interesting, and maybe a way to detect circularity.
moonclimb
Status | In development |
Author | screwtape |
More posts
- What we get out of lispAug 31, 2024
- Rebuild everything dayAug 18, 2024
- Exploratory ProgrammingAug 16, 2024
Comments
Log in with itch.io to leave a comment.
Oops, I forgot to include
before the traverse call, though you got what happened, right.