Non-Local Exits
;; block / return-from: lexical exit
(defun find-negative (list)
(dolist (x list) ; dolist establishes an implicit block named NIL
(when (minusp x) (return x))))
(find-negative '(1 2 -3 4)) ; -3
(defun search-grid (grid target)
(block search
(dotimes (i (array-dimension grid 0))
(dotimes (j (array-dimension grid 1))
(when (eql (aref grid i j) target)
(return-from search (list i j)))))
nil))
;; Every defun establishes a block named after the function: (return-from my-function value)
;; catch / throw: dynamic exit (the tag is looked up at runtime)
(defun deep-search (x) (when (= x 42) (throw 'found x)) nil)
(catch 'found
(dolist (x '(1 42 3)) (deep-search x))
:not-found) ; 42
;; unwind-protect: cleanup that always runs
(defun with-resource-demo ()
(let ((resource (acquire-resource)))
(unwind-protect
(use-resource resource) ; protected form
(release-resource resource)))) ; cleanup forms run on normal exit AND on non-local exits/errors
;; tagbody / go: low-level goto (used inside macros like loop and prog)
(let ((i 0))
(tagbody
top
…