Search code examples
lispelisp

Various forms of looping and iteration in Elisp


I am trying to understand all the looping constructs in Emacs Lisp. In one example I am trying to iterate over a list of symbols and print them to the *message* buffer like so:

(let* ((plist package-activated-list) ;; list of loaded packages
       (sorted-plist (sort plist 'string<)))
  (--map (message (format "%s" it)) sorted-plist))

--map is a function from the package dash.el.

How to do this in pure Elisp?

Now how do I iterate over a list in Elisp, without using other packages.

I have seen some examples using while and dolist macro, for example here:

https://www.gnu.org/software/emacs/manual/html_node/elisp/Iteration.html

But those are destructive, non-functional ways to express a loop.

Coming from Scheme (having worked with it and with SICP some twenty years ago!), I tend to prefer functional, non destructive (does that always lead to recursive?) ways to express ideas.

So what are idiomatic ways to loop over a list of items in Emacs Lisp?

Also: Are there ways to express loops in a functional fashion in Emacs Lisp?

What I have found so far

  1. Loop Macros (from Common Lisp?) prefixed with "cl-*"

https://www.gnu.org/software/emacs/manual/html_node/cl/Loop-Facility.html

  1. Iteration Clauses

https://www.gnu.org/software/emacs/manual/html_node/cl/Iteration-Clauses.html#Iteration-Clauses

  1. Dash.el

https://github.com/magnars/dash.el

Magnar Sveen's excellent package marketed as "A modern list api for Emacs. No 'cl required."

What else is there? Any recommended reading?


Solution

  • dolist is not destructive, and that is probably the most idiomatic way in Emacs Lisp, or Common Lisp for that matter, to loop over a list when you just want to do something with each member in turn:

    (setq *properties* '(prop1 prop2 prop3))
    
    (dolist (p *properties*)
      (print p))
    

    The seq-doseq function does the same thing as dolist, but accepts a sequence argument (e.g., a list, vector, or string):

    (seq-doseq (p *properties*)
      (print p))
    

    If a more functional style is desired, the seq-do function applies a function to the elements of a sequence and returns the original sequence. This function is similar to the Scheme procedure for-each, which is also used for its side effects.

    (seq-do #'(lambda (p) (print p)) *properties*)