The loop macro in emacs lisp

| categories: emacs_lisp | tags:

I was reading The Land Of Lisp chapter on the loop macro in Common Lisp. I am not too familiar with it, or the implementation in emacs-lisp, so in this post we explore what it can do. Here I will explore some uses of the loop macro to do things I used to do in Python all the time.

Here is a simple example to generate a list of numbers with the loop macro..

(loop for i
      below 5
      collect i)
0 1 2 3 4

Evidently, i starts at 0, and increments by one. We can specify a different value like this. Here we use the to token, which also includes the last value.

(loop for i from 2 to 10
  collect i)
2 3 4 5 6 7 8 9 10

IF you want to go backwards:

(loop for i downfrom 10 to 2 collect i)
10 9 8 7 6 5 4 3 2

And if you want an (de)increment different than one, use the by token.

(loop for i downfrom 10 to 2 by 3 collect i)
10 7 4

We can use this to iterate over a list too. Let us collect the square of each element in a simple list. This is similar to the mapcar function.

(loop for i in '(1 2 3 4)
  collect (* i i))
1 4 9 16

You can combine the ideas to get something similar to the enumerate function in python.

(loop for i
      from 0
      for month
      in '(january february march april may june july august september
                   october november december)
      collect (cons i month))
((0 . january)
 (1 . february)
 (2 . march)
 (3 . april)
 (4 . may)
 (5 . june)
 (6 . july)
 (7 . august)
 (8 . september)
 (9 . october)
 (10 . november)
 (11 . december))

The loop stops because we run out of months to iterate over. Here is a variation like the zip function in python.

(loop for element1 in '(a b c d)
      for element2 in '(1 2 3 4)
      collect (list element1 element2))
a 1
b 2
c 3
d 4

We can sum in the loop:

(loop for i in '(100 200 300) sum i)
600

We can conditionally sum things in the loop, e.g. sum only the odd numbers.

(loop for i in '(1 2 3 4 5)
  when (oddp i)
  sum i)
9

We can find the minima and maxima in a list

(loop for i in '(-1 0 1)
  minimize i)
-1
(loop for i in '(-1 0 1)
  maximize i)
1

You may want to do some action in the loop. Say we want to print even numbers from a list.

(loop for i in '(1 2 3 4)
      when (evenp i)
      do (print i))
2

4

There are some ways to break out of a loop using return like this.

(loop for i upto 10
      when (= i 3)
      return 'done
      do (print i))
0

1

2

Alternatively, you can use while/until.

(loop for i downfrom 10
      do (print i)
      until (= i 6))
10

9

8

7

6

Or the while variation:

(loop for i downfrom 10
      do (print i)
      while (> i 6))
10

9

8

7

6

1 Summary

This is not everything the loop macro can do! Here is what the help for that function says.

loop is an alias for `cl-loop' in `cl.el'.

(loop CLAUSE...)

The Common Lisp `loop' macro.
Valid clauses include:
  For clauses:
    for VAR from/upfrom/downfrom EXPR1 to/upto/downto/above/below EXPR2 by EXPR3
    for VAR = EXPR1 then EXPR2
    for VAR in/on/in-ref LIST by FUNC
    for VAR across/across-ref ARRAY
    for VAR being:
      the elements of/of-ref SEQUENCE [using (index VAR2)]
      the symbols [of OBARRAY]
      the hash-keys/hash-values of HASH-TABLE [using (hash-values/hash-keys V2)]
      the key-codes/key-bindings/key-seqs of KEYMAP [using (key-bindings VAR2)]
      the overlays/intervals [of BUFFER] [from POS1] [to POS2]
      the frames/buffers
      the windows [of FRAME]
  Iteration clauses:
    repeat INTEGER
    while/until/always/never/thereis CONDITION
  Accumulation clauses:
    collect/append/nconc/concat/vconcat/count/sum/maximize/minimize FORM
      [into VAR]
  Miscellaneous clauses:
    with VAR = INIT
    if/when/unless COND CLAUSE [and CLAUSE]... else CLAUSE [and CLAUSE...]
    named NAME
    initially/finally [do] EXPRS...
    do EXPRS...
    [finally] return EXPR

For more details, see Info node `(cl)Loop Facility'.

It is obviously quite powerful, although the syntax seems quite different than the usual lisp code I have been writing. It is not clear when this is superior to something like mapcar/mapconcat, or the dolist/dotimes functions.

Copyright (C) 2014 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.7c

Discuss on Twitter