One way to use catch
and throw
is to exit from a doubly nested loop. (In most languages, this would be done with a goto
.) Here we compute (foo i j)
for i and j varying from 0 to 9:
(defun search-foo () (catch 'loop (let ((i 0)) (while (< i 10) (let ((j 0)) (while (< j 10) (if (foo i j) (throw 'loop (list i j))) (setq j (1+ j)))) (setq i (1+ i))))))
If foo
ever returns non-nil
, we stop immediately and return a list of i and j. If foo
always returns nil
, the catch
returns normally, and the value is nil
, since that is the result of the while
.
Here are two tricky examples, slightly different, showing two return points at once. First, two return points with the same tag, hack
:
(defun catch2 (tag) (catch tag (throw 'hack 'yes))) ⇒ catch2
(catch 'hack (print (catch2 'hack)) 'no) -| yes ⇒ no
Since both return points have tags that match the throw
, it goes to the inner one, the one established in catch2
. Therefore, catch2
returns normally with value yes
, and this value is printed. Finally the second body form in the outer catch
, which is 'no
, is evaluated and returned from the outer catch
.
Now let’s change the argument given to catch2
:
(catch 'hack (print (catch2 'quux)) 'no) ⇒ yes
We still have two return points, but this time only the outer one has the tag hack
; the inner one has the tag quux
instead. Therefore, throw
makes the outer catch
return the value yes
. The function print
is never called, and the body-form 'no
is never evaluated.
Copyright © 1990-1996, 1998-2019 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Examples-of-Catch.html