Reading — step 1 of 4
Learn
Common Lisp has the most sophisticated error-handling system of any mainstream language. It splits signaling, handling, and restarting.
Defining a condition (Lisp's exception):
(define-condition not-found-error (error)
((id :initarg :id :reader not-found-id))
(:report (lambda (c stream)
(format stream "not found: ~a" (not-found-id c)))))
Signaling:
(error 'not-found-error :id 42)
;; Or just signal a string:
(error "something failed")
Handling with handler-case:
(handler-case
(lookup-user id)
(not-found-error (e)
(format t "missed: ~a~%" (not-found-id e))
nil))
handler-bind for non-unwinding handlers — the killer feature. Set up handlers that stay on the stack, can decide whether to unwind, and can invoke restarts:
(handler-bind
((division-by-zero (lambda (c) (invoke-restart 'use-zero))))
(compute-with-restart))
Restarts are recovery options the signaler offers:
(defun divide (a b)
(restart-case
(if (zerop b)
(error 'division-by-zero)
(/ a b))
(use-zero ()
:report "Use zero as result"
0)
(provide-default (default)
:report "Provide a default value"
:interactive (lambda () (list (read)))
default)))
When an error fires, the handler decides whether to unwind or to restart and continue. SLIME's debugger lists available restarts.
This system is why Common Lisp interactive debugging is so powerful — you can poke at the running system, fix the problem, and resume.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…