The loop macro in emacs lisp
Posted November 20, 2014 at 09:50 AM | 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 version = 8.2.7c