Skip to content

Instantly share code, notes, and snippets.

@xiongtx
Created September 30, 2016 02:09
Show Gist options
  • Save xiongtx/0fa011f880a68e8bd5b035ef1e1a171d to your computer and use it in GitHub Desktop.
Save xiongtx/0fa011f880a68e8bd5b035ef1e1a171d to your computer and use it in GitHub Desktop.
;; Debugger == interactive restarter
;; If we try to open a non-existent file, we are put into the debugger
(with-open-file (in "nonexistent-file.txt")
(format t "~A~%" (read-line in nil)))
;; The debugger offer a restart that retries the evaluation
(with-open-file (str "nonexistent-file.txt"
:direction :output)
(format str "This file now exists."))
(delete-file "nonexistent-file.txt")
;; Custom restarts
;; We can define our own restarts
(with-simple-restart (foo "Restart with foo.")
(error "How should we restart?"))
;; More generally, we can use `restart-case'
(defun my-symbol-value (name)
(if (boundp name)
(symbol-value name)
(restart-case (error 'unbound-variable :name name)
(use-value (value)
:report "Specify a value to use."
:interactive (lambda ()
(format t "~&Value to use: ")
(list (eval (read))))
value)
(store-value (value)
:report "Specify a value to use and store."
:interactive (lambda ()
(format t "~&Value to use and store: ")
(list (eval (read))))
(setf (symbol-value name) value)
value))))
;; Call (my-symbol-value 'undefined-symbol) in the REPL
;; Programmatic restarts
;; Let's try to programmatically restart based on condition type
(handler-case (+ (my-symbol-value 'undefined-symbol)
(my-symbol-value 'pi))
(unbound-variable (c)
(let ((restart (find-restart 'use-value c)))
(when restart
(invoke-restart restart 17)))))
;; This does not work!
;; Let's try another way
(handler-bind ((unbound-variable
(lambda (c)
(let ((restart (find-restart 'use-value c)))
(when restart
(invoke-restart restart 17))))))
(+ (my-symbol-value 'undefined-symbol)
(my-symbol-value 'pi)))
;; `handler-case' unwinds the stack
;; `handler-bind' does not unwind stack
;; Let's look at some macro expansions!
(ignore-errors (error "An error"))
(with-simple-restart (foo "Simple restart")
(error "An error"))
(handler-case (error "An error")
(error (c)
(declare (ignore c))
"Handled error"))
;; Resources
;; Practical Common Lisp (Peter Seibel)
;; http://www.gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html
;; Common Lisp the Language, 2nd Ed.
;; https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node312.html#SECTION003300000000000000000
;; Clojure versions of CL condition system
;; Talk by Chris Houser:
;; https://www.youtube.com/watch?v=zp0OEDcAro0
;; Write-up of talk:
;; https://gist.github.com/msgodf/6f4e43c112b8e89eee3d
;; Hugo Duncan's Swell (uses Slingshot)
;; https://github.com/hugoduncan/swell
;; https://github.com/scgilardi/slingshot
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment