Is it possible to break out of a dolist
loop? if not, are there alternatives to dolist
that don't involve a while loop and indexing a list?
2 Answers
One option is to use catch
/ throw
:
https://www.gnu.org/software/emacs/manual/html_node/elisp/Catch-and-Throw.html
(catch 'foo
(dolist (x '("a" "b" "c" "d" "e" "f" "g"))
(when (equal x "d")
(throw 'foo x))))
The catch statement evaluates to the value thrown (x
in this case), or the value of the last body form if the throw
function never executes. In the case at hand the dolist
form is the last entry in the body. The optional RESULT
argument of (dolist (VAR LIST [RESULT]) BODY...)
is not specified. Therefore, it evaluates to nil.
As pointed out by @Drew and @Tobias in comments below, the dolist
function that is available without loading the cl
library is defined in subr.el
. Once the cl
library is loaded, however, describing the function with C-h f
reflects that dolist
has been modified as follows: :around advice: ‘cl--wrap-in-nil-block’
. The function return
(which is an alias for cl-return
that is defined in the cl
library) can be used to break the dolist
loop. To load the cl
library, begin with (require 'cl)
:
(dolist (x '("a" "b" "c" "d" "e" "f" "g"))
(when (equal x "d")
(return x)))
-
2+1. Maybe make clearer that without loading library
cl
the version ofdolist
is different (not an alias forcl-dolist
). You can usereturn
(cl-return
) only with the version ofdolist
provided by librarycl
(it is an alias forcl-dolist
). You more or less say that, but it could be clearer - there are two differentdolist
s, and only one lets you usereturn
.– DrewNov 13, 2019 at 5:05 -
1@Drew
dolist
is never an alias forcl-dolist
.cl.el
rather wrapsdolist
into a nil-block by an around advice and(cl-return val)
is essentially(throw nil val)
. So there is not much difference between the two solutions of lawlist. The second solution is just more elegant if cl is available.– TobiasNov 13, 2019 at 5:55 -
1Do not require
cl
. That is depreciated. Better requirecl-macs
orcl-lib
and usecl-dolist
andcl-return
instead ofdolist
andreturn
. Maybe, explicitly state that and give both alternative solutions.– TobiasNov 13, 2019 at 6:03 -
1Citation from the cl info file: "Since the old
cl.el
does not use a clean namespace, Emacs has a policy that packages distributed with Emacs must not loadcl
at run time. (It is ok for them to loadcl
at compile time, witheval-when-compile
, and use the macros it provides.) There is no such restriction on the use ofcl-lib
. New code should usecl-lib
rather thancl
."– TobiasNov 13, 2019 at 6:33 -
1@lawlist here is the thread about cl.el = declaring obsolete: emacs.1067599.n8.nabble.com/…– HubisanNov 13, 2019 at 9:23
The Common Lisp Cookbook has an extensive section on loops. Among other things, as a substitute for dolist you could try a "for" loop and use "when" to exit. For example:
(require 'cl-lib)
(cl-loop for i in '(123 3 22 1 309)
when (< i 2)
return -500
do (print i))
... output ...
123
3
22
-500
while
loop is excluded. IMHO it is the only pre-defined loop avoiding non-local exit when breaking out of a list iteration. It can be head or tail controlled or anything in between.The catch statement evaluates to the value thrown (x in this case), or nil if no value is thrown.
to lawlist's answer. How do you throw without passing a value? TheVALUE
arg ofthrow
is obligatory. Maybe, you meancl-return
where it is optional.