ErgoEmacsEmacsLispBlogEmacsLispBuy Tutorial

Emacs Lisp: Throw & Catch, Exit a Loop

, ,

This page shows you how to exit a loop in emacs lisp.

In many languages, there's “break” or “exit” keywords that you can use to exit a loop. In functional programing, usually you don't use loop/iteration, but sometimes a loop is just what you need.

In elisp, to exit loop, you can use a while loop and check a flag (set a variable to true/false), or use the built-in catch and throw.

Exit a While Loop by Flag

Here's a sample of setting flag:

(let (myList foundFlag-p i)
  
  (setq myList [0 1 2 3 4 5] )
  (setq foundFlag-p nil )
  (setq i 0)

  (while
      (and (not foundFlag-p) (<= i (length myList)))
    
    ;; if found, set foundFlag-p
    (when (equal (elt myList i) 3)
      (setq foundFlag-p t )
      )

    (message "value: %s" i)
    (setq i (1+ i))
    )

  )

Here's a actual example using a flag:

(defun get-new-fpath (ξfPath moveFromToList)
  "Return a new file full path for ξfPath.
moveFromToList is a alist."
  (let ((ξfoundResult nil) (ξi 0) (ξlen (length moveFromToList)) )
    ;; compare to each moved dir.
    (while (and (not ξfoundResult) (< ξi ξlen))
      (when (string-match (concat "\\`" (regexp-quote (car (elt moveFromToList ξi))) ) ξfPath )
        (let (
              (fromDir (car (elt moveFromToList ξi)))
              (toDir (cdr (elt moveFromToList ξi)))
              )
          (setq ξfoundResult (concat toDir (substract-path ξfPath fromDir)) )
          )
        )
      (setq ξi (1+ ξi) )
      )
    (if ξfoundResult ξfoundResult ξfPath )
    )
  )

Using throw & catch

Here's a pseudo-code of throw and catch.

(let (myList)
  (setq myList [0 1 2 3 4 5] )

  ;; map lambda onto a list. If value 3 is found, exit map.
  (catch 'myTagName
    (mapc
     (lambda (x)
       (message "%s" x)
       (when (equal x 3) (throw 'myTagName "VALUE of catch if throw is called") ) )
     myList)

    ;; return value of catch if throw didn't occur
    "normal return VALUE of catch here")
)

The (throw ‹tag› ‹value›) is basically like “goto”. It will jump to the nearest outer (catch ‹tag› …) with matching ‹tag›, and also pass the ‹value› to it.

If (catch ‹tag› … ‹value›) didn't get any throw, it'll return ‹value›, else it'll return the value from throw.

Here's a example using throw and catch.

(defun xahsite-url-is-xah-website-p (myURL)
  "Returns t if MYURL contains a xah domain name, else nil.

See: `xahsite-domain-names'."
  (catch 'myloop
    (mapc (lambda (x)
            (when (string-match-p (format "\\`http://\\(www\\.\\)*%s\.*/*" (regexp-quote x)) myURL)
              (throw 'myloop t)))
          (xahsite-domain-names))
    nil
    )
  )

(info "(elisp) Catch and Throw")

blog comments powered by Disqus