screwlisp proposes a toast

My ANSI common lisp condition ontology eg

| link | Last. 20260308T025540638Z |

Fallow week oh fallow week. I mean, the show with cdg, kmp, and Ramin Honary then Kent Pitman’s epic ensuing mastodon thread featuring Pitman, Ramin, Gosling (edit: Gosling emacs/java was another thread), Doug Merritt, and Roger Crew and others was incredible but it was not something I personally wrote. Someone on libera #commonLisp did ask me whether I found ontologies useful and I said, well, I wrote an ontology of a subset of the ansi common lisp condition system and I use it and find it useful. This article demos the latter.

CL-USER> ***
#<FUNCTION (LAMBDA (NAM &REST KEYS &KEY &ALLOW-OTHER-KEYS)) {5367519B}>
CL-USER> '(ls-condi :ls-dir "~/eg/*.*")
(LS-CONDI :LS-DIR "~/eg/*.*")
CL-USER> (handler-bind
 ((ls-condi #'dir-nams-han) (ls-condi #'ret-nam-han))
 (apply ** *))

"bar" 
"baz" 
"foo" 
#<LS-CONDI {1001523563}> 
"~/eg/*.*"
CL-USER> ***
#<FUNCTION (LAMBDA (NAM &REST KEYS &KEY &ALLOW-OTHER-KEYS)) {5367519B}>
CL-USER> '(ls-condi)
(LS-CONDI)
CL-USER> (handler-bind
 ((ls-condi #'dir-nams-han) (ls-condi #'ret-nam-han))
 (apply ** *))

#<LS-CONDI {100157A983}> 
NIL

ANSI common lisp’s condition system (“We’ve got Pitman errors!”) is a nice and mature way to match different preconditions at runtime and in-local-context to different postconditions via runtime binding handlers operating locally inside an unmodified previous program. The postconditions are local restarts (local continuations) from where the condition was signalled. If you see in tech news that in 2026, new languages are struggling to conceptualize what they are now calling algebraic effects, common lisp has a mature one that was hashed out in the 80s and standardised, released 1994 and is exactly what its cutting edge compilers purport to conform to today. The Common Lisp Condition system. Kent Pitman is one of if not the only world authority on this topic, which clearly subsumes nouveau algebraic effects languages.

Aside, I think lisp’s secret alien technology stature can be seen in its position in the top 25 hot languages of 2025 published by tiobe (“the tiobe index”).

Myself, I was having trouble getting into the storied common lisp condition system, though I know on irc people like Robert Strandh the other day rave about its peerless quality and utility in programming, endemic and today still unique to common lisp. So I wrote a small ontology for constructing pure ansi cl code in my own upper ontology, The Leonardo System (find Erik Sandewall’s mainstream academic publications on it; I am the only source of that one now).

We better hop to it.

  1. We will have a lambda that just signals its arguements.
  2. (ls-condi :ls-dir "~/eg/*.*") obviously means list the contents of the directory ~/eg/.
  3. Apply the lambda to that with two handlers bound to ls-condi.

Well we saw this happening at the start already. This is a reasonable use of a condition because the precondition of the slot ls-dir being bound leads to different handling (so the handler that would have made the error of accessing ls-dir simply declined based on the slot-bound precondition. We can also see that the previously-written-code used signal and contained restarts (just one local restart here) for handlers to reconnect back into the original, local code from handling.

You can see how binding different handlers when you run the program (e.g. call my lambda) make further-extensible and configurable new programs out of a mature program without rewriting that programs code and hence destroying its maturity.

My ontology here was more the structure of my personal exploration of conditions than an examination of every possible condition permitted by the standard. Here is everything I did to make the above example:

cd
clisp -E ISO-8859-1 -modern
(require "asdf")
(uiop:chdir #p"~/leocommunity/tulip/demus/Process/main/")
(load #p"../../../remus/Startup/cl/acleo.leos") nil
(cle)

loadk con-fra-kb
setk con-fra-kb
loadk con-fra-onto
loadk ls-entities

nukfil ~/eg/foo.lisp

filapp ~/eg/foo.lisp [: 1 outok ]
catfil ~/eg/foo.lisp

->

ses.103) nukfil ~/eg/foo.lisp
~/eg/foo.lisp not found.

ses.104) filapp ~/eg/foo.lisp [: 1 outok ]

ses.105) catfil ~/eg/foo.lisp



(defun ok-record nil t) 
ses.106) 
filapp ~/eg/foo.lisp [: 1 outok ]
filapp ~/eg/foo.lisp [: 2 outcon ls-condi ]
filapp ~/eg/foo.lisp [: 2 outhan dir-nams-han ]
filapp ~/eg/foo.lisp [: 2 outhan ret-nam-han ]
filapp ~/eg/foo.lisp [: 2 setres simple-restart-case ]

filapp ~/eg/foo.lisp [: 2 apphan simple-handler-bind ]

catfil ~/eg/foo.lisp

I will include all the lisp code generated by slotting leonardo upper ontology entities into lisp s-expression templates in the appendix at the end. You can see that my actions are about showing entities as things, or redirecting that showing into a lisp file when I am happy with it.

Aside about the quirky filenames: Sandewall uses heavily abbreviated names like this I suppose because in the 60s and 70s there were character limits. I am trying to train myself to adopt them for congruence in maintaining the leonardo system. It is too late for me. It is not too late for you.

If we look at some of my data:

-- simple-handler-bind

[: type handler-bind]
[: mappings 
<[: 2 ls-condi dir-nams-han]
    [: 2 ls-condi ret-nam-han]>]
[: latest-rearchived nil]

---------------------------------------------------------

and my slotting of that into a template using my action outhan:

ses.220) apphan simple-handler-bind

(handler-bind
 ((ls-condi #'dir-nams-han) (ls-condi #'ret-nam-han))
 (apply ** *)) 

I put the leo-expand form (whatever that is) from being subsumed-by Leonardo’s lispdef here in terms of lisp repl special variables since I do repl-driven-development.

of which my ontology is all kind of like that anyway. The one that constructs one restart-case

---------------------------------------------------------
-- just-return-test

[: type restart-test]
[: predicates <<typep t>>]
[: latest-rearchived nil]

---------------------------------------------------------
-- just-return-interactive

[: type restart-interactive]
[: local-vars <x c>]
[: latest-rearchived nil]

---------------------------------------------------------
-- just-return-report

[: type restart-report]
[: format-control-string "just-return w/ ~@{~a~^, ~}."]
[: latest-rearchived nil]

---------------------------------------------------------
-- just-return

[: type restart]
[: test just-return-test]
[: interactive just-return-interactive]
[: report just-return-report]
[: latest-rearchived nil]

(leodef just-ret just-ret (x c)
	(progn
	  (print c)
	  (values x )))
 
---------------------------------------------------------
-- simple-restart-case

[: type restart-case]
[: restarts <just-return>]
[: latest-rearchived nil]

---------------------------------------------------------

is a bit more complicated:

ses.221) setres simple-restart-case

(lambda (nam &rest keys &key &allow-other-keys)
 (restart-case (apply 'signal nam keys)
  (just-return (x c) :interactive
   (lambda nil
    (let (x c)
     (loop :for var :in '(x c) :do
      (format *query-io* "Expression for ~a:~%" var)
      (set var (eval (read *query-io*))))
     (list x c)))
   :report
   (lambda (s)
    (apply 'format s "just-return w/ ~@{~a~^, ~}." '(x c)))
   :test (lambda (c) (and (apply #'typep c '(t)) t))
   (progn (print c) (values x))))) 

You can see it specifies all three of the keywords for each restart (just one, here) with some kind of default.

Appendix: The classically generated lisp code my little ontology makes

The only difficult I think you might have is that the last form is clearly a repl-only thing tat must be accessed like:

  1. (that generated lambda definition with restarts)

  2. '(ls-condi :ls-dir path/to/dir/*.*) the ‘ls’ query

  3. (the generated handler-bind form in terms of the last two repl outputs, i.e. * and **.

ses.222) catfil ~/eg/foo.lisp



(defun ok-record nil t) 

(define-condition ls-condi nil
 ((ls-dir :initarg :ls-dir :accessor ls-dir))) 
(defun dir-nams-han (c)
 (unless
  (and (apply #'typep c '(ls-condi))
   (apply #'slot-boundp c '(ls-dir)))
  (return-from dir-nams-han))
 (progn
  (mapc 'print (mapcar 'pathname-name (directory (ls-dir c))))
  (output-ok))) 
(defun ret-nam-han (c)
 (unless (and (apply #'typep c '(ls-condi)))
  (return-from ret-nam-han))
 (let ((x (and (slot-boundp c 'ls-dir) (ls-dir c))))
  (invoke-restart 'just-return x c) (ok-record))) 
(lambda (nam &rest keys &key &allow-other-keys)
 (restart-case (apply 'signal nam keys)
  (just-return (x c) :interactive
   (lambda nil
    (let (x c)
     (loop :for var :in '(x c) :do
      (format *query-io* "Expression for ~a:~%" var)
      (set var (eval (read *query-io*))))
     (list x c)))
   :report
   (lambda (s)
    (apply 'format s "just-return w/ ~@{~a~^, ~}." '(x c)))
   :test (lambda (c) (and (apply #'typep c '(t)) t))
   (progn (print c) (values x))))) 
(handler-bind
 ((ls-condi #'dir-nams-han) (ls-condi #'ret-nam-han))
 (apply ** *)) 
ses.223) 

What did I get out of this

Handling only-known-at-runtime preconditions by binding handlers and restarts at runtime, that handle and locally restart back into the unchanged much-previously-written program code is a defining and signature feature of common lisp that just now high-tech new languages are trying to copy out of lisp thought-leadership under the name algebraic effects. I am not angry about new fashion languages wanting to have the great stuff common lisp has, but you could just use ansi common lisp, and you must cite ansi common lisp when you follow its leadership so other people can understand where you are trying to go.

Ontologically, I guess I defined types, attributes and subsumption relations in my con-fra-kb’s con-fra-onto ontology i.e. types entityfile. Then, I wrote ls-entities. Only entities of established types for that kb get written / persisted in ls-entities, so this was one utility of ontology. Only entities of types defined in this domain ontology are in other knowledgebase files. It is a bit quirky that I used types subsumed-by my Leonardo system foundation ontology’s lispdef type, which it uses for lisp code implementations of actions.

Then, my ontology was very much about the forward problem. If I have these sequences of constraint definitions, or a little tree of features to specify a restart and a restart-case, I want to have code I can pitch (eev) to my other emacs buffer from my upper ontology’s expert shell, or dump into files with some file operations. This is not the same thing as me trying to independently formalise the ansi common lisp standard’s definition of its condition system.

I dunno, hopefully you got something out of my diatribe here.

screwlisp proposes a toast