News for hackers. Stuff that matters.
Re:The Common Lisp Condition System – Upcoming Book by kazinator on Wednesday July 15, 2020 @12:45PM (#23847829)
TXR Lisp:

  This is the TXR Lisp interactive listener of TXR 240.
  Quit with :quit or Ctrl-D on empty line. Ctrl-X ? for cheatsheet.
  1> (defun filter-using-exceptions(list)
       (build  ;; build macro: implicit, procedural list building
         (each ((item list))
            (catch (throw 'keep-it? item)
                   (yes () (add item))
                   (no ())))))
  filter-using-exceptions
  2> (handle (filter-using-exceptions (range 1 10))
             (keep-it? (item) (if (evenp item) (throw 'yes) (throw 'no))))
  (2 4 6 8 10)
Variation:

  3> (defun filter-using-exceptions (list)
       (build
         (each ((item list))
            (catch (throw 'keep-it? item)
                   (yes () (add item))
                   (no ())
                   (substitute (this) (add this))))))
  filter-using-exceptions
  4> (handle (filter-using-exceptions (range 1 10))
             (keep-it? (item)
               (cond
                  ((< item 5) (throw 'yes))
                  ((= item 5) (throw 'substitute 42))
                  (t (throw 'no)))))
  (1 2 3 4 42)
An exception handling system in which exceptions throwing does not unwind can do thing similar to generators or continuations, but without any of the implementation complexities and overhead. Plus the flexibilities of the exception type system: handlers found by subclass matching, and the potential for a handler to examine and decline exceptions so it can go on to match another handler.

In TXR, I simplified the concept by eliminating the duality of conditions and restarts. There are only exceptions. catch frames take an exception with unwinding. handle frames take an exception without unwinding (they can potentially decline it after looking at it). In the above example, keep-it? is an exception and so are yes, no and substitute.

So, why would you do the above instead of just, say:

  5> (mappend (lambda (item)
                (cond
                    ((< item 5) (list item))
                    ((= item 5) (list 42))
                    (t nil)))
              (range 1 10))
  (1 2 3 4 42)
You almost certainly wouldn't; it's just an illustration. There is a relationship between the two in that the mappend is an incomplete specification of a behavior which requires a function to be specified by the caller.

In the exception example, that is happening also: a function is required from the caller to complete the behavior. But that function isn't passed as a parameter; it is dynamically bound as a handler which is labeled by an exception symbol. The function doesn't simply return a value, but chooses from a menu of restart points.

That points to a whole different set of ways of organizing the code, and options for extending and maintaining it.

There are no comments on this comment yet.