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