1
0
Fork 0
cl-sites/lispcookbook.github.io/cl-cookbook/iteration.html

1521 lines
46 KiB
HTML
Raw Normal View History

2023-10-25 11:23:21 +02:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="generator" content=
"HTML Tidy for HTML5 for Linux version 5.2.0">
<title>Loop, iteration, mapping</title>
<meta charset="utf-8">
<meta name="description" content="A collection of examples of using Common Lisp">
<meta name="viewport" content=
"width=device-width, initial-scale=1">
<link rel="icon" href=
"assets/cl-logo-blue.png"/>
<link rel="stylesheet" href=
"assets/style.css">
<script type="text/javascript" src=
"assets/highlight-lisp.js">
</script>
<script type="text/javascript" src=
"assets/jquery-3.2.1.min.js">
</script>
<script type="text/javascript" src=
"assets/jquery.toc/jquery.toc.min.js">
</script>
<script type="text/javascript" src=
"assets/toggle-toc.js">
</script>
<link rel="stylesheet" href=
"assets/github.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<h1 id="title-xs"><a href="index.html">The Common Lisp Cookbook</a> &ndash; Loop, iteration, mapping</h1>
<div id="logo-container">
<a href="index.html">
<img id="logo" src="assets/cl-logo-blue.png"/>
</a>
<div id="searchform-container">
<form onsubmit="duckSearch()" action="javascript:void(0)">
<input id="searchField" type="text" value="" placeholder="Search...">
</form>
</div>
<div id="toc-container" class="toc-close">
<div id="toc-title">Table of Contents</div>
<ul id="toc" class="list-unstyled"></ul>
</div>
</div>
<div id="content-container">
<h1 id="title-non-xs"><a href="index.html">The Common Lisp Cookbook</a> &ndash; Loop, iteration, mapping</h1>
<!-- Announcement we can keep for 1 month or more. I remove it and re-add it from time to time. -->
<p class="announce">
📹 💻
<a style="font-size: 120%" href="https://www.udemy.com/course/common-lisp-programming/?couponCode=LISPMACROSPOWER" title="This course is under a paywall on the Udemy platform. Several videos are freely available so you can judge before diving in. vindarel is (I am) the main contributor to this Cookbook."> Discover vindarel's Lisp course in videos with this September coupon.</a>
<strong>
Recently added: 18 videos on MACROS.
</strong>
<a style="font-size: 90%" href="https://github.com/vindarel/common-lisp-course-in-videos/">Learn more</a>.
</p>
<p class="announce-neutral">
📕 <a href="index.html#download-in-epub">Get the EPUB and PDF</a>
</p>
<div id="content"
<!-- needs some text before the first heading -->
<h2 id="introduction-loop-iterate-for-mapcar-series">Introduction: loop, iterate, for, mapcar, series</h2>
<p><strong><a href="http://www.lispworks.com/documentation/lw51/CLHS/Body/m_loop.htm">loop</a></strong>
is the built-in macro for iteration.</p>
<p>Its simplest form is <code>(loop (print "hello"))</code>: this will print forever.</p>
<p>A simple iteration over a list is:</p>
<pre><code class="language-lisp">(loop for x in '(1 2 3)
do (print x))
</code></pre>
<p>It prints whats needed but returns <code>nil</code>.</p>
<p>If you want to return a list, use <code>collect</code>:</p>
<pre><code class="language-lisp">(loop for x in '(1 2 3)
collect (* x 10))
;; (10 20 30)
</code></pre>
<p>The Loop macro is different than most Lisp expressions in having a complex
internal domain-specific language that doesnt use s-expressions.
So you need to read Loop expressions with half of your brain in Lisp mode, and
the other half in Loop mode. You love it or you hate it.</p>
<p>Think of Loop expressions as having four parts: expressions that set up
variables that will be iterated, expressions that conditionally terminate the
iteration, expressions that do something on each iteration, and expressions that
do something right before the Loop exits. In addition, Loop expressions can
return a value. It is very rare to use all of these parts in a given Loop
expression, but you can combine them in many ways.</p>
<p><strong><a href="https://common-lisp.net/project/iterate/doc/index.html">iterate</a></strong> is a
popular iteration macro that aims at being simpler, “lispier” and more
predictable than <code>loop</code>, besides being extensible. However it isnt built-in,
so you have to import it:</p>
<pre><code>(ql:quickload "iterate")
(use-package :iterate)
</code></pre>
<p>Iterate looks like this:</p>
<pre><code class="language-lisp">(iter (for i from 1 to 5)
(collect (* i i)))
</code></pre>
<p>(if you use loop and iterate in the same package, you might run into name conflicts)</p>
<p>Iterate also comes with <code>display-iterate-clauses</code> that can be quite handy:</p>
<pre><code class="language-lisp">(display-iterate-clauses '(for))
;; FOR PREVIOUS &amp;OPTIONAL INITIALLY BACK Previous value of a variable
;; FOR FIRST THEN Set var on first, and then on subsequent iterations
;; ...
</code></pre>
<p>Much of the examples on this page that are valid for loop are also valid for iterate,
with minor modifications.</p>
<p><strong><a href="https://github.com/Shinmera/for/">for</a></strong> is an extensible iteration
macro that is often shorter than loop, that “unlike loop is extensible
and sensible, and unlike iterate does not require code-walking and is
easier to extend”.</p>
<p>It has the other advantage of having one construct that works for all
data structures (lists, vectors, hash-tables…): in doubt, just use
<code>for… over</code>:</p>
<pre><code class="language-lisp">(for:for ((x over &lt;your data structure&gt;))
(print …))
</code></pre>
<p>You also have to quickload it:</p>
<pre><code>(ql:quickload "for")
</code></pre>
<p>Well also give examples with <strong><code>mapcar</code></strong> and <code>map</code>, and eventually
with their friends <code>mapcon</code>, <code>mapcan</code>, <code>maplist</code>, <code>mapc</code> and <code>mapl</code>
which E. Weitz categorizes very well in his “Common Lisp Recipes”,
chap. 7. The one you are certainly accustomed to from other languages is
<code>mapcar</code>: it takes a function, one or more lists as arguments,
applies the function on each <em>element</em> of the lists one by one and
returns a list of result.</p>
<pre><code class="language-lisp">(mapcar (lambda (it) (+ it 10)) '(1 2 3))
(11 12 13)
</code></pre>
<p><code>map</code> is generic, it accepts list and vectors as arguments, and
expects the type for its result as first argument:</p>
<pre><code class="language-lisp">(map 'vector (lambda (it) (+ it 10)) '(1 2 3))
;; #(11 12 13)
(map 'list (lambda (it) (+ it 10)) #(1 2 3))
;; (11 12 13)
(map 'string (lambda (it) (code-char it)) '#(97 98 99))
;; "abc"
</code></pre>
<p>The other constructs have their advantages in some situations ;) They
either process the <em>tails</em> of lists, or <em>concatenate</em> the return
values, or dont return anything. Well see some of them.</p>
<p>If you like <code>mapcar</code>, use it a lot, and would like a quicker and
shorter way to write lambdas, then you might like one of those
<a href="https://github.com/CodyReichert/awesome-cl#lambda-shorthands">lambda shorthand libraries</a>.</p>
<p>Here is an example with <a href="https://github.com/windymelt/cl-punch/">cl-punch</a>:</p>
<pre><code class="language-lisp">(mapcar ^(* _ 10) '(1 2 3))
;; (10 20 30)
</code></pre>
<p>and voilà :) We wont use this more in this recipe, but feel free to do.</p>
<p>Last but not least, you might like
<strong><a href="http://series.sourceforge.net/">series</a></strong>,
a library that describes itself as combining aspects of sequences,
streams, and loops. Series expressions look like operations on
sequences (= functional programming), but can achieve the same high level of efficiency as a
loop. Series first appeared in “Common Lisp the Language”, in the
appendix A (it nearly became part of the language). Series looks like
this:</p>
<pre><code class="language-lisp">(collect
(mapping ((x (scan-range :from 1 :upto 5)))
(* x x)))
;; (1 4 9 16 25)
</code></pre>
<p><code>series</code> is good, but its function names are different from what we
find in functional languages today. You might like the <a href="https://github.com/cbeo/gtwiwtg">“Generators
The Way I Want Them Generated”</a>
library. It is a lazy sequences library, similar to <code>series</code> although
younger and not as complete, with a “modern” API with words like <code>take</code>, <code>filter</code>,
<code>for</code> or <code>fold</code>, and that is easy to use.</p>
<pre><code class="language-lisp">(range :from 20)
;; #&lt;GTWIWTG::GENERATOR! {1001A90CA3}&gt;
(take 4 (range :from 20))
;; (20 21 22 23)
</code></pre>
<p>At the time of writing, GTWIWTG is licensed under the GPLv3.</p>
<h2 id="recipes">Recipes</h2>
<h3 id="looping-forever-return">Looping forever, return</h3>
<pre><code class="language-lisp">(loop
(print "hello"))
</code></pre>
<p><code>return</code> can return a result:</p>
<pre><code class="language-lisp">(loop for i in '(1 2 3)
when (&gt; i 1)
return i)
2
</code></pre>
<h3 id="looping-a-fixed-number-of-times">Looping a fixed number of times</h3>
<h4 id="dotimes">dotimes</h4>
<pre><code class="language-lisp">(dotimes (n 3)
(print n))
;; =&gt;
;; 0
;; 1
;; 2
;; NIL
</code></pre>
<p>Here <code>dotimes</code> returns <code>nil</code>. There are two ways to return a value. First, you can set a result form in the lambda list:</p>
<pre><code class="language-lisp">(dotimes (n 3 :done)
;; ^^^^^ result form. It can be a s-expression.
(print n))
;; =&gt;
;; 0
;; 1
;; 2
;; :DONE
</code></pre>
<p>Or you can use <code>return</code> with return values:</p>
<pre><code class="language-lisp">(dotimes (i 3)
(if (&gt; i 1)
(return :early-exit!)
(print i)))
;; =&gt;
;; 0
;; 1
;; :EARLY-EXIT!
</code></pre>
<h4 id="loop-repeat">loop… repeat</h4>
<pre><code class="language-lisp">(loop repeat 10
do (format t "Hello!~%"))
</code></pre>
<p>This prints 10 times “hello” and returns <code>nil</code>.</p>
<pre><code class="language-lisp">(loop repeat 10 collect (random 10))
;; (5 1 3 5 4 0 7 4 9 1)
</code></pre>
<p>with <code>collect</code>, this returns a list.</p>
<h4 id="series">Series</h4>
<pre><code class="language-lisp">(iterate ((n (scan-range :below 10)))
(print n))
</code></pre>
<h3 id="looping-an-infinite-number-of-times-cycling-over-a-circular-list">Looping an infinite number of times, cycling over a circular list</h3>
<p>First, as shown above, we can simply use <code>(loop ...)</code> to loop
infinitely. Here we show how to loop on a list forever.</p>
<p>We can build an infinite list by setting its last element to the list itself:</p>
<pre><code class="language-lisp">(loop with list-a = '(1 2 3)
with infinite-list = (setf (cdr (last list-a)) list-a)
for item in infinite-list
repeat 8
collect item)
;; (1 2 3 1 2 3 1 2)
</code></pre>
<p>Illustration: <code>(last '(1 2 3))</code> is <code>(3)</code>, a list, or rather a cons cell, whose <code>car</code> is 3 and <code>cdr</code> is NIL. See the <a href="data-structures.html">data-structures chapter</a> for a reminder. This is the representation of <code>(list 3)</code>:</p>
<pre><code>[o|/]
|
3
</code></pre>
<p>The representation of <code>(list 1 2 3)</code>:</p>
<pre><code>[o|o]---[o|o]---[o|/]
| | |
1 2 3
</code></pre>
<p>By setting the <code>cdr</code> of the last element to the list itself, we make it recur on itself.</p>
<p>A notation shortcut is possible with the <code>#=</code> syntax:</p>
<pre><code class="language-lisp">(defparameter *list-a* '#1=(1 2 3 . #1#))
(setf *print-circle* t) ;; don't print circular lists forever
*list-a*
</code></pre>
<p>If you need to alternate only between two values, use <code>for … then</code>:</p>
<pre><code class="language-lisp">(loop repeat 4
for up = t then (not up)
do (print up))
T
NIL
T
NIL
</code></pre>
<h3 id="iterates-for-loop">Iterates for loop</h3>
<p>For lists and vectors:</p>
<pre><code class="language-lisp">(iter (for item in '(1 2 3))
(print item))
(iter (for i in-vector #(1 2 3))
(print i))
</code></pre>
<p>or, a generalized iteration clause for lists and vectors, use
<code>in-sequence</code> (youll pay a speed penalty).</p>
<p>Looping over a hash-table is also straightforward:</p>
<pre><code class="language-lisp">(let ((h (let ((h (make-hash-table)))
(setf (gethash 'a h) 1)
(setf (gethash 'b h) 2)
h)))
(iter (for (k v) in-hashtable h)
(print k)))
;; b
;; a
</code></pre>
<p>In fact, take a look <a href="https://common-lisp.net/project/iterate/doc/Sequence-Iteration.html">here</a>,
or <code>(display-iterate-clauses '(for))</code> to know about iterating over</p>
<ul>
<li>symbols in-package</li>
<li>forms - or lines, or whatever-you-wish - in-file, or in-stream</li>
<li>elements in-sequence - sequences can be vectors or lists</li>
</ul>
<h3 id="looping-over-a-list">Looping over a list</h3>
<h4 id="dolist">dolist</h4>
<pre><code class="language-lisp">(dolist (item '(1 2 3))
(print item))
</code></pre>
<p><code>dolist</code> returns <code>nil</code>.</p>
<h4 id="loop">loop</h4>
<p>with <code>in</code>, no surprises:</p>
<pre><code class="language-lisp">(loop for x in '(a b c)
do (print x))
;; A
;; B
;; C
;; NIL
</code></pre>
<pre><code class="language-lisp">(loop for x in '(a b c)
collect x)
;; (A B C)
</code></pre>
<p>With <code>on</code>, we loop over the cdr of the list:</p>
<pre><code class="language-lisp">(loop for i on '(1 2 3) do (print i))
;; (1 2 3)
;; (2 3)
;; (3)
</code></pre>
<h4 id="mapcar">mapcar</h4>
<pre><code class="language-lisp">(mapcar (lambda (x)
(print (* x 10)))
'(1 2 3))
10
20
30
(10 20 30)
</code></pre>
<p><code>mapcar</code> returns the results of the lambda function as a list.</p>
<h4 id="series-1">Series</h4>
<pre><code class="language-lisp">(iterate ((item (scan '(1 2 3))))
(print item))
</code></pre>
<p><code>scan-sublists</code> is the equivalent of <code>loop for ... on</code>:</p>
<pre><code class="language-lisp">(iterate ((i (scan-sublists '(1 2 3))))
(print i))
</code></pre>
<h3 id="looping-over-a-vector">Looping over a vector</h3>
<h4 id="loop-across">loop: <code>across</code></h4>
<pre><code class="language-lisp">(loop for i across #(1 2 3) do (print i))
</code></pre>
<h4 id="series-2">Series</h4>
<pre><code class="language-lisp">(iterate ((i (scan #(1 2 3))))
(print i))
</code></pre>
<h3 id="looping-over-a-hash-table">Looping over a hash-table</h3>
<p>We create a hash-table:</p>
<pre><code class="language-lisp">(defparameter h (make-hash-table))
(setf (gethash 'a h) 1)
(setf (gethash 'b h) 2)
</code></pre>
<h4 id="looping-over-keys-and-values">Looping over keys and values</h4>
<p>Looping over keys:</p>
<pre><code class="language-lisp">(loop for k being the hash-key of h do (print k))
;; b
;; a
</code></pre>
<p>Looping over values uses the same concept but with the <code>hash-value</code> keyword instead of <code>hash-key</code>:</p>
<pre><code class="language-lisp">(loop for k being the hash-value of h do (print k))
;; 1
;; 2
</code></pre>
<p>Looping over key-values pairs:</p>
<pre><code class="language-lisp">(loop for k
being the hash-key
using (hash-value v) of h
do (format t "~a ~a~%" k v))
b 2
a 1
</code></pre>
<h4 id="iterate">iterate</h4>
<p>Use <code>in-hashtable</code>:</p>
<pre><code class="language-lisp">(iter (for (key value) in-hashtable h)
(collect (list key value)))
</code></pre>
<h4 id="for">for</h4>
<p>the same with <code>for</code>:</p>
<pre><code class="language-lisp">(for:for ((it over h))
(print it))
(A 1)
(B 2)
NIL
</code></pre>
<h4 id="maphash">maphash</h4>
<p>The lambda function of <code>maphash</code> takes two arguments: the key and the
value:</p>
<pre><code class="language-lisp">(maphash (lambda (key val)
(format t "key: ~a val:~a~&amp;" key val))
h)
;; key: A val:1
;; key: B val:2
;; NIL
</code></pre>
<p>See also <a href="http://www.lispworks.com/documentation/HyperSpec/Body/m_w_hash.htm">with-hash-table-iterator</a>.</p>
<h4 id="dohash">dohash</h4>
<p>Only because we like this topic, we introduce another library, <a href="https://github.com/yitzchak/trivial-do/">trivial-do</a>. It has the <code>dohash</code> macro, that ressembles <code>dolist</code>:</p>
<pre><code class="language-lisp">(dohash (key value h)
(format t "key: ~A, value: ~A~%" key value))
</code></pre>
<h4 id="series-3">Series</h4>
<pre><code class="language-lisp">(iterate (((k v) (scan-hash h)))
(format t "~&amp;~a ~a~%" k v))
</code></pre>
<h3 id="looping-over-two-lists-in-parallel">Looping over two lists in parallel</h3>
<h4 id="loop-1">loop</h4>
<pre><code class="language-lisp">(loop for x in '(a b c)
for y in '(1 2 3)
collect (list x y))
;; ((A 1) (B 2) (C 3))
</code></pre>
<p>To return a flat list, use <code>nconcing</code> instead of <code>collect</code>:</p>
<pre><code class="language-lisp">(loop for x in '(a b c)
for y in '(1 2 3)
nconcing (list x y))
(A 1 B 2 C 3)
</code></pre>
<p>If a list is smaller than the other one, loop stops at the end of the small one:</p>
<pre><code class="language-lisp">(loop for x in '(a b c)
for y in '(1 2 3 4 5)
collect (list x y))
;; ((A 1) (B 2) (C 3))
</code></pre>
<p>We could loop over the biggest list and manually access the elements
of the smaller one by index, but it would quickly be
inefficient. Instead, we can tell <code>loop</code> to extend the short list.</p>
<pre><code class="language-lisp">(loop for y in '(1 2 3 4 5)
for x-list = '(a b c) then (cdr x-list)
for x = (or (car x-list) 'z)
collect (list x y))
;; ((A 1) (B 2) (C 3) (Z 4) (Z 5))
</code></pre>
<p>The trick is that the notation <code>for … = … then (cdr …)</code> (note the <code>=</code>
and the role of <code>then</code>) shortens our intermediate list at each
iteration (thanks to <code>cdr</code>). It will first be <code>'(a b c)</code>, the initial
value, then we will get the <code>cdr</code>: <code>(2 3)</code>, then <code>(3)</code>, then
<code>NIL</code>. And both <code>(car NIL)</code> and <code>(cdr NIL)</code> return <code>NIL</code>, so we are
good.</p>
<h4 id="mapcar-1">mapcar</h4>
<pre><code class="language-lisp">(mapcar (lambda (x y)
(list x y))
'(a b c)
'(1 2 3))
;; ((A 1) (B 2) (C 3))
</code></pre>
<p>or simply:</p>
<pre><code class="language-lisp">(mapcar #'list
'(a b c)
'(1 2 3))
;; ((A 1) (B 2) (C 3))
</code></pre>
<p>Return a flat list:</p>
<pre><code class="language-lisp">(mapcan (lambda (x y)
(list x y))
'(a b c)
'(1 2 3))
;; (A 1 B 2 C 3)
</code></pre>
<h4 id="series-4">Series</h4>
<pre><code class="language-lisp">(collect
(#Mlist (scan '(a b c))
(scan '(1 2 3))))
</code></pre>
<p>A more efficient way, when the lists are known to be of equal length:</p>
<pre><code class="language-lisp">(collect
(mapping (((x y) (scan-multiple 'list
'(a b c)
'(1 2 3))))
(list x y)))
</code></pre>
<p>Return a flat list:</p>
<pre><code class="language-lisp">(collect-append ; or collect-nconc
(mapping (((x y) (scan-multiple 'list
'(a b c)
'(1 2 3))))
(list x y)))
</code></pre>
<h3 id="nested-loops">Nested loops</h3>
<h4 id="loop-2">loop</h4>
<pre><code class="language-lisp">(loop for x from 1 to 3
collect (loop for y from 1 to x
collect y))
;; ((1) (1 2) (1 2 3))
</code></pre>
<p>To return a flat list, use <code>nconcing</code> instead of the first <code>collect</code>.</p>
<h4 id="iterate-1">iterate</h4>
<pre><code class="language-lisp">(iter outer
(for i below 2)
(iter (for j below 3)
(in outer (collect (list i j)))))
;; ((0 0) (0 1) (0 2) (1 0) (1 1) (1 2))
</code></pre>
<h4 id="series-5">Series</h4>
<pre><code class="language-lisp">(collect
(mapping ((x (scan-range :from 1 :upto 3)))
(collect (scan-range :from 1 :upto x))))
</code></pre>
<h3 id="computing-an-intermediate-value">Computing an intermediate value</h3>
<p>Use <code>=</code>.</p>
<p>With <code>for</code>:</p>
<pre><code class="language-lisp">(loop for x from 1 to 3
for y = (* x 10)
collect y)
;; (10 20 30)
</code></pre>
<p>With <code>with</code>, the difference being that the value is computed only
once:</p>
<pre><code class="language-lisp">(loop for x from 1 to 3
for y = (* x 10)
with z = x
collect (list x y z))
;; ((1 10 1) (2 20 1) (3 30 1))
</code></pre>
<p>The HyperSpec defines the <code>with</code> clause like this:</p>
<pre><code>with-clause::= with var1 [type-spec] [= form1] {and var2 [type-spec] [= form2]}*
</code></pre>
<p>so it turns out we can specify the type before the <code>=</code> and chain the <code>with</code> with <code>and</code>:</p>
<pre><code class="language-lisp">(loop for x from 1 to 3
for y integer = (* x 10)
with z integer = x
collect (list x y z))
</code></pre>
<pre><code class="language-lisp">(loop for x upto 3
with foo = :foo
and bar = :bar
collect (list x foo bar))
</code></pre>
<p>We can also give <code>for</code> a <code>then</code> clause that will be called at each iteration:</p>
<pre><code class="language-lisp">(loop repeat 3
for intermediate = 10 then (incf intermediate)
do (print intermediate))
10
11
12
</code></pre>
<p>Heres a trick to alternate a boolean:</p>
<pre><code class="language-lisp">(loop repeat 4
for up = t then (not up)
do (print up))
T
NIL
T
NIL
</code></pre>
<h3 id="loop-with-a-counter">Loop with a counter</h3>
<h4 id="loop-3">loop</h4>
<p>Iterate through a list, and have a counter iterate in parallel. The length of
the list determines when the iteration ends. Two sets of actions are defined,
one of which is executed conditionally.</p>
<pre><code class="language-lisp">* (loop for x in '(a b c d e)
for y from 1
when (&gt; y 1)
do (format t ", ")
do (format t "~A" x)
)
A, B, C, D, E
NIL
</code></pre>
<p>We could also write the preceding loop using the IF construct.</p>
<pre><code class="language-lisp">* (loop for x in '(a b c d e)
for y from 1
if (&gt; y 1)
do (format t ", ~A" x)
else do (format t "~A" x)
)
A, B, C, D, E
NIL
</code></pre>
<h4 id="series-6">Series</h4>
<p>By iterating on multiple series in parallel, and using an infinite
range, we can make a counter.</p>
<pre><code class="language-lisp">(iterate ((x (scan '(a b c d e)))
(y (scan-range :from 1)))
(when (&gt; y 1) (format t ", "))
(format t "~A" x))
</code></pre>
<h3 id="ascending-descending-order-limits">Ascending, descending order, limits</h3>
<h4 id="loop-4">loop</h4>
<p><code>from… to…</code>:</p>
<pre><code class="language-lisp">(loop for i from 0 to 10
do (print i))
;; 0 1 2 3 4 5 6 7 8 9 10
</code></pre>
<p><code>from… below…</code>: this stops at 9:</p>
<pre><code class="language-lisp">(loop for i from 0 below 10
do (print i))
</code></pre>
<p>Similarly, use <code>from 10 downto 0</code> (10…0) and <code>from 10 above 0</code> (10…1).</p>
<h4 id="series-7">Series</h4>
<p><code>:from ... :upto</code>, including the upper limit:</p>
<pre><code class="language-lisp">(iterate ((i (scan-range :from 0 :upto 10)))
(print i))
</code></pre>
<p><code>:from ... :below</code>, excluding the upper limit:</p>
<pre><code class="language-lisp">(iterate ((i (scan-range :from 0 :below 10)))
(print i))
</code></pre>
<h3 id="steps">Steps</h3>
<h4 id="loop-5">loop</h4>
<p>with <code>by</code>:</p>
<pre><code class="language-lisp">(loop for i from 1 to 10 by 2
do (print i))
</code></pre>
<p>if you use <code>by (1+ (random 3))</code>, the random is evaluated only once, as
if it was in a closure:</p>
<pre><code class="language-lisp">(let ((step (random 3)))
(loop for i from 1 to 10 by (+ 1 step)
do (print i)))
</code></pre>
<p>The step must always be a positive number. If you want to count down, see above.</p>
<h4 id="series-8">Series</h4>
<p>with <code>:by</code>:</p>
<pre><code class="language-lisp">(iterate ((i (scan-range :from 1 :upto 10 :by 2)))
(print i))
</code></pre>
<h3 id="loop-and-conditionals">Loop and conditionals</h3>
<h4 id="loop-6">loop</h4>
<p>with <code>if</code>, <code>else</code> and <code>finally</code>:</p>
<pre><code class="language-lisp">;; https://riptutorial.com/common-lisp/example/11095/conditionally-executing-loop-clauses
(loop repeat 10
for x = (random 100)
if (evenp x)
collect x into evens
else
collect x into odds
finally (return (values evens odds)))
</code></pre>
<pre><code>(42 82 24 92 92)
(55 89 59 13 49)
</code></pre>
<p>Combining multiple clauses in an if body requires special syntax (<code>and
do</code>, <code>and count</code>):</p>
<pre><code class="language-lisp"> (loop repeat 10
for x = (random 100)
if (evenp x)
collect x into evens
and do (format t "~a is even!~%" x)
else
collect x into odds
and count t into n-odds
finally (return (values evens odds n-odds)))
</code></pre>
<pre><code>46 is even!
8 is even!
76 is even!
58 is even!
0 is even!
(46 8 76 58 0)
(7 45 43 15 69)
5
</code></pre>
<h4 id="iterate-2">iterate</h4>
<p>Translating (or even writing!) the above example using iterate is straight-forward:</p>
<pre><code class="language-lisp">(iter (repeat 10)
(for x = (random 100))
(if (evenp x)
(progn
(collect x into evens)
(format t "~a is even!~%" x))
(progn
(collect x into odds)
(count t into n-odds)))
(finally (return (values evens odds n-odds))))
</code></pre>
<h4 id="series-9">Series</h4>
<p>The preceding loop would be done a bit differently in Series. <code>split</code>
sorts one series into multiple according to provided boolean series.</p>
<pre><code class="language-lisp">(let* ((number (#M(lambda (n) (random 100))
(scan-range :below 10)))
(parity (#Mevenp number)))
(iterate ((n number) (p parity))
(when p (format t "~a is even!~%" n)))
(multiple-value-bind (evens odds) (split number parity)
(values (collect evens)
(collect odds)
(collect-length odds))))
</code></pre>
<p>Note that although <code>iterate</code> and the three <code>collect</code> expressions are
written sequentially, only one iteration is performed, the same as the
example with loop.</p>
<h3 id="begin-the-loop-with-a-clause-initially">Begin the loop with a clause (initially)</h3>
<pre><code class="language-lisp">(loop initially
(format t "~a " 'loop-begin)
for x below 3
do (format t "~a " x))
;; LOOP-BEGIN 0 1 2
</code></pre>
<p><code>initially</code> also exists with <code>iterate</code>.</p>
<h3 id="terminate-the-loop-with-a-test-until-while">Terminate the loop with a test (until, while)</h3>
<h4 id="loop-7">loop</h4>
<pre><code class="language-lisp">(loop for x in '(1 2 3 4 5)
until (&gt; x 3)
collect x)
;; (1 2 3)
</code></pre>
<p>the same, with <code>while</code>:</p>
<pre><code class="language-lisp">(loop for x in '(1 2 3 4 5)
while (&lt; x 4)
collect x)
</code></pre>
<h4 id="series-10">Series</h4>
<p>We truncate the series with <code>until-if</code>, then collect from its result.</p>
<pre><code class="language-lisp">(collect
(until-if (lambda (i) (&gt; i 3))
(scan '(1 2 3 4 5))))
</code></pre>
<h3 id="loop-print-and-return-a-result">Loop, print and return a result</h3>
<h4 id="loop-8">loop</h4>
<p><code>do</code> and <code>collect</code> can be combined in one expression</p>
<pre><code class="language-lisp">(loop for x in '(1 2 3 4 5)
while (&lt; x 4)
do (format t "x is ~a~&amp;" x)
collect x)
x is 1
x is 2
x is 3
(1 2 3)
</code></pre>
<h4 id="series-11">Series</h4>
<p>By mapping, we can perform a side effect and also collect items</p>
<pre><code class="language-lisp">(collect
(mapping ((x (until-if (complement (lambda (x) (&lt; x 4)))
(scan '(1 2 3 4 5)))))
(format t "x is ~a~&amp;" x)
x))
</code></pre>
<h3 id="named-loops-and-early-exit">Named loops and early exit</h3>
<h4 id="loop-9">loop</h4>
<p>The special <code>loop named</code> foo syntax allows you to create a loop that
you can exit early from. The exit is performed using <code>return-from</code>,
and can be used from within nested loops.</p>
<pre><code class="language-lisp">;; useless example
(loop named loop-1
for x from 0 to 10 by 2
do (loop for y from 0 to 100 by (1+ (random 3))
when (&lt; x y)
do (return-from loop-1 (values x y))))
0
2
</code></pre>
<p>Sometimes, you want to return early but execute the <code>finally</code> clause
anyways. Use <a href="http://www.lispworks.com/documentation/HyperSpec/Body/m_loop_f.htm#loop-finish"><code>loop-finish</code></a>.</p>
<pre><code class="language-lisp">(loop for x from 0 to 100
do (print x)
when (&gt;= x 3)
return x
finally (print :done)) ;; &lt;-- not printed
;; 0
;; 1
;; 2
;; 3
;; 3
(loop for x from 0 to 100
do (print x)
when (&gt;= x 3)
do (loop-finish)
finally (print :done)
(return x))
;; 0
;; 1
;; 2
;; 3
;; :DONE
;; 3
</code></pre>
<p>It is most needed when some computation must take place in the <code>finally</code> clause.</p>
<h4 id="loop-shorthands-for-whenreturn">Loop shorthands for when/return</h4>
<p>Several actions provide shorthands for combinations of when/return:</p>
<pre><code class="language-lisp">* (loop for x in '(foo 2)
thereis (numberp x))
T
</code></pre>
<pre><code class="language-lisp">* (loop for x in '(foo 2)
never (numberp x))
NIL
</code></pre>
<pre><code class="language-lisp">* (loop for x in '(foo 2)
always (numberp x))
NIL
</code></pre>
<p>They correspond to the functions <code>some</code>, <code>notany</code> and <code>every</code>:</p>
<pre><code class="language-lisp">(some #'numberp '(foo 2))
(notany #'numberp '(foo 2))
(every #'numberp '(foo 2))
</code></pre>
<h4 id="series-12">Series</h4>
<p>A block is manually created and returned from.</p>
<pre><code class="language-lisp">(block loop-1
(iterate ((x (scan-range :from 0 :upto 10 :by 2)))
(iterate ((y (scan-range :from 0 :upto 100 :by (1+ (random 3)))))
(when (&lt; x y)
(return-from loop-1 (values x y))))))
</code></pre>
<h3 id="count">Count</h3>
<h4 id="loop-10">loop</h4>
<pre><code class="language-lisp">(loop for i from 1 to 3 count (oddp i))
;; 2
</code></pre>
<h4 id="series-13">Series</h4>
<pre><code class="language-lisp">(collect-length (choose-if #'oddp (scan-range :from 1 :upto 3)))
</code></pre>
<h3 id="summation">Summation</h3>
<h4 id="loop-11">loop</h4>
<pre><code class="language-lisp">(loop for i from 1 to 3 sum (* i i))
;; 14
</code></pre>
<p>Summing into a variable:</p>
<pre><code class="language-lisp">(loop for i from 1 to 3
sum (* i i) into total
do (print i)
finally (print total))
1
2
3
14
</code></pre>
<h4 id="series-14">Series</h4>
<pre><code class="language-lisp">(collect-sum (#M(lambda (i) (* i i))
(scan-range :from 1 :upto 3)))
</code></pre>
<h3 id="max-min">max, min</h3>
<h4 id="loop-12">loop</h4>
<pre><code class="language-lisp">(loop for i from 1 to 3 maximize (mod i 3))
;; 2
</code></pre>
<p>and <code>minimize</code>.</p>
<h4 id="series-15">Series</h4>
<pre><code class="language-lisp">(collect-max (#M(lambda (i) (mod i 3))
(scan-range :from 1 :upto 3)))
</code></pre>
<p>and <code>collect-min</code>.</p>
<h3 id="destructuring-aka-pattern-matching-against-the-list-or-dotted-pairs">Destructuring, aka pattern matching against the list or dotted pairs</h3>
<h4 id="loop-13">loop</h4>
<pre><code class="language-lisp">(loop for (a b) in '((x 1) (y 2) (z 3))
collect (list b a) )
;; ((1 X) (2 Y) (3 Z))
</code></pre>
<pre><code class="language-lisp">(loop for (x . y) in '((1 . a) (2 . b) (3 . c)) collect y)
;; (A B C)
</code></pre>
<p>Use <code>nil</code> to ignore a term:</p>
<pre><code class="language-lisp">(loop for (a nil) in '((x 1) (y 2) (z 3))
collect a )
;; (X Y Z)
</code></pre>
<h5 id="iterating-2-by-2-over-a-list">Iterating 2 by 2 over a list</h5>
<p>To iterate over a list, 2 items at a time we use a combination of <code>on</code>, <code>by</code> and destructuring.</p>
<p>We use <code>on</code> to loop over the rest (the <code>cdr</code>) of the list.</p>
<pre><code class="language-lisp">(loop for rest on '(a 2 b 2 c 3)
collect rest)
;; ((A 2 B 2 C 3) (2 B 2 C 3) (B 2 C 3) (2 C 3) (C 3) (3))
</code></pre>
<p>We use <code>by</code> to skip one element at every iteration (<code>(cddr list)</code> is equivalent to <code>(rest (rest list))</code>)</p>
<pre><code class="language-lisp">(loop for rest on '(a 2 b 2 c 3) by #'cddr
collect rest)
;; ((A 2 B 2 C 3) (B 2 C 3) (C 3))
</code></pre>
<p>Then we add destructuring to bind only the first two items at each iteration:</p>
<pre><code class="language-lisp">(loop for (key value) on '(a 2 b 2 c 3) by #'cddr
collect (list key (* 2 value)))
;; ((A 2) (B 4) (C 6))
</code></pre>
<h4 id="series-16">Series</h4>
<p>In general, with <code>destructuring-bind</code>:</p>
<pre><code class="language-lisp">(collect
(mapping ((l (scan '((x 1) (y 2) (z 3)))))
(destructuring-bind (a b) l
(list b a))))
</code></pre>
<p>But for alists, <code>scan-alist</code> is provided:</p>
<pre><code class="language-lisp">(collect
(mapping (((a b) (scan-alist '((1 . a) (2 . b) (3 . c)))))
b))
</code></pre>
<h2 id="iterate-unique-features-lacking-in-loop">Iterate unique features lacking in loop</h2>
<p><code>iterate</code> has some other things unique to it.</p>
<p>If you are a newcomer in Lisp, its perfectly OK to keep this section for
later. You could very well spend your career in Lisp without resorting
to those features… although they might turn out useful one day.</p>
<h3 id="no-rigid-order-for-clauses">No rigid order for clauses</h3>
<p><code>loop</code> requires that all <code>for</code> clauses appear before the loop body,
for example before a <code>while</code>. Its ok for <code>iter</code> to not follow this
order:</p>
<pre><code class="language-lisp">(iter (for x in '(1 2 99)
(while (&lt; x 10))
(for y = (print x))
(collect (list x y)))
</code></pre>
<h3 id="accumulating-clauses-can-be-nested">Accumulating clauses can be nested</h3>
<p><code>collect</code>, <code>appending</code> and other accumulating clauses can appear anywhere:</p>
<pre><code class="language-lisp">(iter (for x in '(1 2 3))
(case x
(1 (collect :a))
;; ^^ iter keyword, nested in a s-expression.
(2 (collect :b))))
</code></pre>
<h3 id="finders-finding">Finders: <code>finding</code></h3>
<p><code>iterate</code> has <a href="https://common-lisp.net/project/iterate/doc/Finders.html#Finders">finders</a>.</p>
<blockquote>
<p>A finder is a clause whose value is an expression that meets some condition.</p>
</blockquote>
<p>We can use <code>finding</code> followed by <code>maximizing</code>, <code>minimizing</code> or <code>such-that</code>.</p>
<p>Heres how to find the longest list in a list of lists:</p>
<pre><code class="language-lisp">(iter (for elt in '((a) (b c d) (e f)))
(finding elt maximizing (length elt)))
=&gt; (B C D)
</code></pre>
<p>The rough equivalent in LOOP would be:</p>
<pre><code class="language-lisp">(loop with max-elt = nil
with max-key = 0
for elt in '((a) (b c d) (e f))
for key = (length elt)
do
(when (&gt; key max-key)
(setf max-elt elt
max-key key))
finally (return max-elt))
=&gt; (B C D)
</code></pre>
<p>There could be more than one <code>such-that</code> clause:</p>
<pre><code class="language-lisp"> (iter (for i in '(7 -4 2 -3))
(if (plusp i)
(finding i such-that (evenp i))
(finding (- i) such-that (oddp i))))
;; =&gt; 2
</code></pre>
<p>We can also write <code>such-that #'evenp</code> and <code>such-that #'oddp</code>.</p>
<h3 id="control-flow-next-iteration">Control flow: <code>next-iteration</code></h3>
<p>It is like “continue” and loop doesnt have it.</p>
<blockquote>
<p>Skips the remainder of the loop body and begins the next iteration of the loop.</p>
</blockquote>
<p><code>iterate</code> also has <code>first-iteration-p</code> and <code>(if-first-time then else)</code>.</p>
<p>See <a href="https://common-lisp.net/project/iterate/doc/Control-Flow.html#Control-Flow">control flow</a>.</p>
<h3 id="generators">Generators</h3>
<p>Use <code>generate</code> and <code>next</code>. A generator is lazy, it goes to the next value when said explicitly.</p>
<pre><code class="language-lisp">(iter (for i in '(1 2 3 4 5))
(generate c in-string "black")
(if (oddp i) (next c))
(format t "~a " c))
;; b b l l a
;; NIL
</code></pre>
<h3 id="variable-backtracking-previous-vs-parallel-binding">Variable backtracking (<code>previous</code>) VS parallel binding</h3>
<p><code>iterate</code> allows us to get the previous value of a variable:</p>
<pre><code class="language-lisp">(iter (for el in '(a b c d e))
(for prev-el previous el)
(collect (list el prev-el)))
;; =&gt; ((A NIL) (B A) (C B) (D C) (E D))
</code></pre>
<p>In this case however we can do it with <code>loop</code>s parallel binding <code>and</code>, which is unsupported in <code>iterate</code>:</p>
<pre><code class="language-lisp">(loop for el in '(a b c d e)
and prev-el = nil then el
collect (list el prev-el))
</code></pre>
<h3 id="more-clauses">More clauses</h3>
<ul>
<li><code>in-string</code> can be used explicitly to iterate character by character over a string. With loop, use <code>across</code>.</li>
</ul>
<pre><code class="language-lisp">(iter (for c in-string "hello")
(collect c))
;; =&gt; (#\h #\e #\l #\l #\o)
</code></pre>
<ul>
<li><code>loop</code> offers <code>collecting</code>, <code>nconcing</code>, and <code>appending</code>. <code>iterate</code> has these and also <code>adjoining</code>, <code>unioning</code>, <code>nunioning</code>, and <code>accumulating</code>.</li>
</ul>
<pre><code class="language-lisp">(iter (for el in '(a b c a d b))
(adjoining el))
;; =&gt; (A B C D)
</code></pre>
<p>(<code>adjoin</code> is a set operation)</p>
<ul>
<li><code>loop</code> has <code>summing</code>, <code>counting</code>, <code>maximizing</code>, and <code>minimizing</code>. <code>iterate</code> also includes <code>multiplying</code> and <code>reducing</code>. reducing is the generalized reduction builder:</li>
</ul>
<pre><code class="language-lisp">(iter (with dividend = 100)
(for divisor in '(10 5 2))
(reducing divisor by #'/ initial-value dividend))
;; =&gt; 1
</code></pre>
<h3 id="iterate-is-extensible">Iterate is extensible</h3>
<pre><code class="language-lisp">(defmacro dividing-by (num &amp;keys (initial-value 0))
`(reducing ,num by #'/ initial-value ,initial-value))
(iter (for i in '(10 5 2))
(dividing-by i :initial-value 100))
=&gt; 1
</code></pre>
<p>but <a href="https://common-lisp.net/project/iterate/doc/Rolling-Your-Own.html#Rolling-Your-Own">there is more to it, see the documentation</a>.</p>
<p>We saw libraries extending <code>loop</code>, for example <a href="http://clsql.kpe.io/manual/loop-tuples.html">CLSQL</a>, but they are
full of feature flag checks (<code>#+(or allegro clisp-aloop cmu openmcl
sbcl scl)</code>) and they call internal modules
(<code>ansi-loop::add-loop-path</code>, <code>sb-loop::add-loop-path</code> etc).</p>
<h2 id="custom-series-scanners">Custom series scanners</h2>
<p>If we often scan the same type of object, we can write our own scanner
for it: the iteration itself can be factored out. Taking the example
above, of scanning a list of two-element lists, well write a scanner
that returns a series of the first elements and a series of the
second.</p>
<pre><code class="language-lisp">(defun scan-listlist (listlist)
(declare (optimizable-series-function 2))
(map-fn '(values t t)
(lambda (l)
(destructuring-bind (a b) l
(values a b)))
(scan listlist)))
(collect
(mapping (((a b) (scan-listlist '((x 1) (y 2) (z 3)))))
(list b a)))
</code></pre>
<h2 id="shorter-series-expressions">Shorter series expressions</h2>
<p>Consider this series expression:</p>
<pre><code class="language-lisp">(collect-sum (mapping ((i (scan-range :length 5)))
(* i 2)))
</code></pre>
<p>Its a bit longer than it needs to be, the <code>mapping</code> forms only
purpose is to bind the variable <code>i</code>, and <code>i</code> is used in only one
place. Series has a “hidden feature” that allows us to simplify this
expression to the following:</p>
<pre><code class="language-lisp">(collect-sum (* 2 (scan-range :length 5)))
</code></pre>
<p>This is called implicit mapping and can be enabled in the call to
<code>series::install</code>:</p>
<pre><code class="language-lisp">(series::install :implicit-map t)
</code></pre>
<p>When using implicit mapping, the <code>#M</code> reader macro demonstrated above
becomes redundant.</p>
<h2 id="loop-gotchas">Loop gotchas</h2>
<ul>
<li>the keyword <code>it</code>, often used in functional constructs, can be
recognized as a loop keyword. Dont use it inside a loop.</li>
</ul>
<h2 id="iterate-gotchas">Iterate gotchas</h2>
<p>It breaks on the function <code>count</code>:</p>
<pre><code class="language-lisp">(iter (for i from 1 to 10)
(sum (count i '(1 3 5))))
</code></pre>
<p>It doesnt recognize the built-in <code>count</code> function and instead signals a condition.</p>
<p>It works in loop:</p>
<pre><code class="language-lisp">(loop for i from 1 to 10
sum (count i '(1 3 5 99)))
;; 3
</code></pre>
<h2 id="appendix-list-of-loop-keywords">Appendix: list of loop keywords</h2>
<p><strong>Name Clause</strong></p>
<pre><code>named
</code></pre>
<p><strong>Variable Clauses</strong></p>
<pre><code>initially finally for as with
</code></pre>
<p><strong>Main Clauses</strong></p>
<pre><code>do collect collecting append
appending nconc nconcing into count
counting sum summing maximize return loop-finish
maximizing minimize minimizing doing
thereis always never if when
unless repeat while until
</code></pre>
<p>These dont introduce clauses:</p>
<pre><code>= and it else end from upfrom
above below to upto downto downfrom
in on then across being each the hash-key
hash-keys of using hash-value hash-values
symbol symbols present-symbol
present-symbols external-symbol
external-symbols fixnum float t nil of-type
</code></pre>
<p>But note that its the parsing that determines what is a keyword. For example in:</p>
<pre><code class="language-lisp">(loop for key in hash-values)
</code></pre>
<p>Only <code>for</code> and <code>in</code> are keywords.</p>
<p>©Dan Robertson on <a href="https://stackoverflow.com/questions/52236803/list-of-loop-keywords">Stack Overflow</a>.</p>
<h2 id="credit-and-references">Credit and references</h2>
<h3 id="loop-14">Loop</h3>
<ul>
<li><a href="http://www.ai.sri.com/pkarp/loop.html">Tutorial for the Common Lisp Loop Macro</a> by Peter D. Karp</li>
<li><a href="http://www.unixuser.org/~euske/doc/cl/loop.html">Common Lisps Loop Macro Examples for Beginners</a> by Yusuke Shinyama</li>
<li><a href="https://gitlab.com/vancan1ty/clstandard_build">Section 6.1 The LOOP Facility, of the draft Common Lisp Standard (X3J13/94-101R)</a> - the (draft) standard provides background information on Loop development, specification and examples. <a href="https://gitlab.com/vancan1ty/clstandard_build/-/blob/master/cl-ansi-standard-draft-w-sidebar.pdf">Single PDF file available</a></li>
<li><a href="https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node235.html">26. Loop by Jon L White, edited and expanded by Guy L. Steele Jr.</a> - from the book “Common Lisp the Language, 2nd Edition”. Strong connection to the draft above, with supplementing comments and examples.</li>
</ul>
<h3 id="iterate-3">Iterate</h3>
<ul>
<li><a href="https://common-lisp.net/project/iterate/doc/index.html">The Iterate Manual</a> -by Jonathan Amsterdam and Luís Oliveira</li>
<li><a href="https://common-lisp-libraries.readthedocs.io/iterate/">iterate - Pseudocodic Iteration</a> - by Shubhamkar Ayare</li>
<li><a href="https://sites.google.com/site/sabraonthehill/loop-v-iter">Loop v Iterate - SabraOnTheHill</a></li>
<li><a href="https://web.archive.org/web/20170713081006/https://items.sjbach.com/211/comparing-loop-and-iterate">Comparing loop and iterate</a> - by Stephen Bach (web archive)</li>
</ul>
<h3 id="series-17">Series</h3>
<ul>
<li><a href="https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node347.html">Common Lisp the Language (2nd Edition) - Appendix A. Series</a></li>
<li><a href="http://series.sourceforge.net/">SERIES for Common Lisp - Richard C. Waters</a></li>
</ul>
<h3 id="others">Others</h3>
<ul>
<li>See also: <a href="https://lisp-journey.gitlab.io/blog/snippets-functional-style-more/">more functional constructs</a> (do-repeat, take,…)</li>
</ul>
<p class="page-source">
Page source: <a href="https://github.com/LispCookbook/cl-cookbook/blob/master/iteration.md">iteration.md</a>
</p>
</div>
<script type="text/javascript">
// Don't write the TOC on the index.
if (window.location.pathname != "/cl-cookbook/") {
$("#toc").toc({
content: "#content", // will ignore the first h1 with the site+page title.
headings: "h1,h2,h3,h4"});
}
$("#two-cols + ul").css({
"column-count": "2",
});
$("#contributors + ul").css({
"column-count": "4",
});
</script>
<div>
<footer class="footer">
<hr/>
&copy; 2002&ndash;2023 the Common Lisp Cookbook Project
<div>
📹 Discover <a style="color: darkgrey; text-decoration: underline", href="https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358">vindarel's Lisp course on Udemy</a>
</div>
</footer>
</div>
<div id="toc-btn">T<br>O<br>C</div>
</div>
<script text="javascript">
HighlightLisp.highlight_auto({className: null});
</script>
<script type="text/javascript">
function duckSearch() {
var searchField = document.getElementById("searchField");
if (searchField && searchField.value) {
var query = escape("site:lispcookbook.github.io/cl-cookbook/ " + searchField.value);
window.location.href = "https://duckduckgo.com/?kj=b2&kf=-1&ko=1&q=" + query;
// https://duckduckgo.com/params
// kj=b2: blue header in results page
// kf=-1: no favicons
}
}
</script>
<script async defer data-domain="lispcookbook.github.io/cl-cookbook" src="https://plausible.io/js/plausible.js"></script>
</body>
</html>