Loop/Iterate

Loop Simple Form

loop form* ⇒ result*

Evaluate forms forever in a loop within an implict block named nil.

(setf i 0)
(loop
  (print i)
  (if (< i 10)
    (incf i)
    (return))) ;⇒ NIL [prints 0...10]

Loop Extended Form

loop [name] [variable-clause*] [main-clause*] ⇒ result*

Use loop keywords to iterate over forms and accumulate values.

(loop for item in (list 'a 'b 'c 'd)
  do (print item))                         ;⇒ NIL [prints A, B, C, D]

(loop for item in (list 'a 'b 'c 'd)
  collect item)                            ;⇒ (A B C D)

(loop for item across (vector 'a 'b 'c 'd)
  collect item)                            ;⇒ (A B C D)

(loop for item in '(1 2 3 4)
      for x = (1+ item)
  collect (* item x))                      ;⇒ (2 5 12 20)

(loop for x on (list 10 20 30)
  collect x)                               ;⇒ ((10 20 30) (20 30) (30))

Variables declared using with are local and cease to exists when the loop terminates.

(loop with x = 0
      with y = (1+ x)
  return (list x y))    ;⇒ (0 1)

Counting

(loop for i upto 4 collect i) ;⇒ (0 1 2 3 4)

Iterate

(ql:quickload :iterate)

iterate:iter [clauses*] forms*

A powerful iteration facility that provides abstractions for many common iteration patterns and allows for the definition of additional patterns. While it is similar to loop, iterate offers a more Lisp-like syntax and enhanced extensibility.

Numerical Iteration

repeat n

Iterate loop n times. If n is <= 0 the loop will not execute.

(iter (repeat 5)
  (print 'hello))   ;⇒ NIL [prints HELLO five times]

for var sequence-keywords

Iterate over a sequence of numbers with a variable and one or more keywords that provide the bounds and step size of the iteration. Valid sequence-keywords are: from, upfrom, downfrom, to, downto, above, below and by.

(for i from 5)              ;i ⇒ 5 6 7 ... (same as upfrom)
(for i downfrom 0)          ;i ⇒ 0 -1 -2 ...
(for i from 1 to 3)         ;i ⇒ 1 2 3
(for i from 5 downto 3)     ;i ⇒ 5 4 3
(for i from 1 below 3)      ;i ⇒ 1 2
(for i from 3 above 1)      ;i ⇒ 3 2
(for i from 1 to 3 by 2)    ;i ⇒ 1 3
(for i from 1 below 3 by 2) ;i ⇒ 1

Sequence Iteration

The step-function, which defaults to cdr, is used to obtain the next sublist.

Valid sequence-keywords are as before: from, upfrom, downfrom, to, downto, above, below and by. In addition, with-index takes a symbol as argument and uses it for the index variable.

for var in list [by step-function]

Set var to successive elements of list.

(iter (for x in '(a b c d) by #'cddr)
  (collect x))                        ;⇒ (A C)

for var on list [by step-function]

Set var to successive sublists of list.

(iter (for x on '(a b c))
  (collect x))            ;⇒ ((A B C) (B C) (C))

for var in-sequence seq sequence-keywords

Set var to successive elements of seq.

(iter (for x in-sequence '(a b c) with-index i)
  (collect (list i x)))                         ;⇒ ((0 A) (1 B) (2 C))

for var index-of-sequence sequence sequence-keywords

Set var to the index number of sequence element.

(iter (for i index-of-sequence #(a b c))
  (collect i))                           ;⇒ (0 1 2)

for var in-vector vector sequence-keywords

Set var to successive elements of vector.

(iter (for x in-vector #(a b c))
  (collect x))                   ;⇒ (A B C)

for var index-of-vector vector sequence-keywords

Set var to the index number of vector element.

(iter (for i index-of-vector #(a b c))
  (collect i))                         ;⇒ (0 1 2)

for var in-string string sequence-keywords

Set var to successive elements of string.

(iter (for x in-string "hello" downfrom 4)
  (collect x))                             ;⇒ (#\o #\l #\l #\e #\h)

for var index-of-string string sequence-keywords

Set var to the index number of string character.

(iter (for i index-of-string "hello" downfrom 4)
  (collect i))                                   ;⇒ (4 3 2 1 0)

for (key value) in-hashtable table

Iterate over the keys and values of a hash-table.

(setf ht (alexandria:plist-hash-table '(:a 1 :b 2)))
(iter (for (key val) in-hashtable ht)
  (collect (list key val)))           ;⇒ ((:A 1) (:B 2))

for var in-package package [external-only ext]

Iterate over all symbols in a package, or only external symbols if specified.

(iter (for sym in-package :iterate external-only t)
  (collect sym))       :⇒ (SUM FIRST-ITERATION-P NCONCING FIRST-TIME-P ...)

for (sym access-type pkg) in-packages (packages) [having-access (symbol-types)]

Iterates over all symbols from the list of packages and having visibility given by symbol-types, which defaults to the list (:external :internal :inherited).

(iter (for (sym access-type pkg) in-packages '(:iterate) having-access (:external))
  (collect (list sym access-type pkg)))

for var in-file name [using reader]

Opens the file name (string or pathname) and iterate over its contents. reader defaults to read and will bind var to successive forms in the file. The file is closed no matter how the iterate loop exits.

(iter (for line in-file "/etc/passwd" using #'read-line)
  (collect line))   ;⇒ ("root:*:0:0:System Administrator:/var/root:/bin/sh" ...)

for var in-stream stream [using reader]

Like for…in-file except that stream should be an existing stream object that supports input operations.

(with-input-from-string (in "hello 1 2 three")
  (iter (for sym in-stream in)
    (collect line)))                           ;⇒ (HELLO 1 2 THREE)

Variable Binding

with var [= value]

Causes var to be bound to value before the loop body is entered.

(setf n 0)
(iter (for x in '(a b c))
      (with i = n)
  (incf n)
  (collect (list i x)))   ;⇒ ((0 A) (0 B) (0 C))

for var = form

On each iteration, form is evaluated and var is set to its value.

(setf n 0)
(iter (for x in '(a b c))
      (for i = n)
  (incf n)
  (collect (list i x)))   ;⇒ ((0 A) (1 B) (2 C))

for var initially init-expr then then-expr

Before loop begins, var is set to init-expr; after the first iteration, it is set to then-expr.

(iter (repeat 4)
      (for i initially 10 then (1+ i))
  (collect i))                         ;⇒ (10 11 12 13)

for var first first-expr then then-expr

On the first iteration, var is set to init-form; on subsequent iterations, it is set to then-expr. This differs from for…initially in that var is set inside the loop body.

for pvar previous var [initially init] [back n]

Sets pvar to the previous value of var, another loop variable.

(iter (for x in '(1 2 3))
      (for y previous x initially 0)
  (collect (list x y)))              ;⇒ ((1 0) (2 1) (3 2))

Accumulate

collect value [into var at place result-type type]

Returns a sequence of values produced from each iteration. Each value is placed in the collected sequence at the start or end (default).

(iter (for i in '(1 2 3))
  (collect x)             ;⇒ (1 2 3)

(iter (for i in '(1 2 3))
  (collect x at start)    ;⇒ (3 2 1)

adjoining value [into var test test at place result-type type]

Like collect, but only adds the value if it is not already present.

(iter (for i in '(1 2 3 2 3 3 1))
  (adjoining i))                  ;⇒ (1 2 3)

appending value [into var at place]

Like collect, but using append.

nconcing value [into var at place]

Like collect, but using nconc.

unioning value [into var test test at place]

Like collect, but using union. Assumes that the value contains no duplicates.

nunioning value [into var test test at place]

Like collect, but using nunion. Assumes that the value contains no duplicates.

accumulate value by fn [initial-value init-val into var]

The general-purpose accumulation clause. Function fn takes two arguments, the value and the value accumulated so far in the iteration, and it should return the updated value. If no initial-value is supplied, nil is used.

Reduce

An iteration pattern in which the results of successive applications of a binary operation are accumulated.

sum value [into var]

On each iteration, value is added to a variable, which is initially bound to zero.

(iter (for i in '(1 2 3 4))
  (sum i))                  ;⇒ 10

multiply value [into var]

Like sum, but the initial value of the result is 1, and is updated by multiplying value into it.

(iter (for i in '(1 2 3 4))
  (multiply i))             ;⇒ 24

counting value [into var]

On each iteration, if value evaluates to non-nil, increment the counter, which initially starts at zero.

(iter (for x in '(a 2 nil d))
  (counting x))               ;⇒ 3

maximize value [into var]

Evaluate value on each iteration and store the maximum in the accumulation variable.

(iter (for i in '(1 4 2 2))
  (maximize i))             ;⇒ 4

minimize value [into var]

Evaluate value on each iteration and store the minimum in the accumulation variable.

(iter (for i in '(1 4 2 2))
  (minimize i))             ;⇒ 1

reducing value by fn [initial-value init-val into var]

The general way to perform reductions. Function fn takes two arguments, the first is the value computed so far and the second is the value. It should return a new value.

(iter (for i in '(1 2 3 4))
  (reducing i by #'(lambda (x y) (+ x y)))) ;⇒ 10

Tests

finding value such-that test [into var on-failure failure-value]

If test ever evaluates to non-nil, the loop is stopped and the current value is returned.

(iter (for i in '(1 2 3))
  (finding i such-that #'oddp))  ;⇒ 1

(iter (for i in '(1 2 3))
  (finding i such-that #'evenp)) ;⇒ 2

finding expr maximizing m-expr [into var]

Computes the maximum value of m-expr over all iterations, and returns the value of the corresponding expr.

(iter (for lst in '((a b c) (x y) (1 2 3 4)))
  (finding lst maximizing (length lst)))      ;⇒ (1 2 3 4)

finding expr minimizing m-expr [into var]

Computes the minimum value of m-expr over all iterations, and returns the value of the corresponding expr.

(iter (for lst in '((a b c) (x y) (1 2 3 4)))
  (finding lst minimizing #'length))          ;⇒ (X Y)

first-iteration-p

Returns t in the first cycle of the loop, otherwise nil.

(iter (repeat 3)
  (collect (first-iteration-p))) ;⇒ (T NIL NIL)

first-time-p

Returns t the first time the expression is evaluated, and then nil forever.

(iter (for i in '(1 2 3))
  (collect (list (first-time-p) i))) ;⇒ ((T 1) (NIL 2) (NIL 3))

always expr

If expr ever evaluates to nil, then nil is immediately returned; the epilogue code is not executed.

(iter (for i in '(1 2 3 4))
      (always (evenp i)))   ;⇒ NIL

never expr

Like (always (not expr)), but does not influence the last value returned by a possible other always clause.

(iter (for i in '(2 4 6 8))
      (always (evenp i)))   ;⇒ T

thereis expr

If expr is ever non-nil, its value is immediately returned without running epilogue code.

(iter (for i in '(1 2 3 4))
      (thereis (characterp i))) ;⇒ NIL

Control Flow

Alter the usual flow of control in a loop.

finish

Stops the loop and runs the epilogue code.

(iter (for x in '(a b c 1 2 3))
  (if (numberp x)
    (finish))
  (collect x))                  ;⇒ (A B C)

leave [value]

Immediately returns value (default nil) from the loop, skipping the epilogue code. Equivalent to using return-from.

(iter (for x in '(a b c 1 2 3))
  (if (numberp x)
    (leave x)))                 ;⇒ 1

next-iteration

Skips the remainder of the loop body and begins the next iteration.

(iter (for x in '(a b c 1 2 d e))
  (if (numberp x)
    (next-iteration))
  (collect x))                    ;⇒ (A B C D E)

while expr

If expr ever evaluates to nil, the loop stops and the epilogue code is run. Equivalent to (if (not expr) (finish)).

(iter (for x in '(1 2 a b 3 4))
  (while (numberp x))
  (collect x))                    ;⇒ (1 2)

until expr

Equivalent to (if expr (finish)).

(iter (for x in '(a b c 1 2 d e))
  (until (numberp x))
  (collect x))                    ;⇒ (A B C)

if-first-time then [else]

If this clause is executed for the first time in the iterate form, the then code is evaluated; otherwise the else code is evaluated.

(iter (for i in '(1 2 3 4))
  (collect (if-first-time
             nil
             i)))           ;⇒ (NIL 2 3 4)

Code Placement

For control over where code is placed in a loop.

initially forms*

Place forms in the prologue section of the loop. They are executed once, before the loop body is entered.

after-each forms*

Place forms at the end of the loop body, where they are executed after each iteration.

else forms*

Place forms in the epilogue section of the loop, where they are executed if this else clause is never met during execution of the loop and the loop terminates normally.

finally forms*

Place forms in the epilogue section of the loop, where they are executed after the loop has terminated normally.

finally-protected forms*

Place forms in the second form of an unwind-protect outside the loop. They are always executed after the loop has terminated, regardless of how the termination occurred.

in name &forms*

Evaluate forms as if they were part of the iterate form name.

(iter outer (for i in '(1 2 3))
  (iter (for j in '(10 20))
    (in outer (collect (* i j))))) ;⇒ (10 20 20 40 30 60)

Destructuring

In many places where a variable is expected, a list can be written instead. The value to be assigned is destructured according to the pattern described by the list.

(for (x y) in '((1 2) (3 4)))
(for (key . val) in alist)
(for (values (a . b) c d) = (three-valued-function ...))

dsetq template expr

Performs destructuring of expr using template. May be used outside of an iterate form. Yields the primary value of expr.

(dsetq (values a b) (floor 4.5)) ;⇒ 4
(list a b)                       ;⇒ (4 0.5)

Extend

Write new clauses that embody new iteration patterns.

for var next expr

Set var to expr each time through the loop. Destructuring is performed. When the clause is used as a generator, expr is the code that is executed when (next var) is encountered.

for var do-next form

Evaluate form each time through the loop. Its value is not set to var; that’s done in form. var is only present so that iterate knows it is a driver variable.

Advanced

defmacro-clause arglist body-form

Defines a new iterate clause. arglist is a list of symbols which are alternating keywords and arguments.

(defmacro-clause (MULTIPLY expr &optional INTO var)
  `(reducing ,expr by #'* into ,var initial-value 1))

defmacro-driver arglist body-form

Defines a driver clause in both the for and generate forms, and provides a parameter generate which body can examine to determine how it was invoked.

defsynonym syn word

Makes syn a synonym for the existing iterate keyword word.

defclause-sequence element-name index-name &keys*

Provides a simple way to define sequence clauses. Generates two clauses, one for iterating over the sequence’s elements, the other for iterating over its indices.

display-iterate-clauses [clause-spec]

Displays a list of [iterate][iter] clauses. If clause-spec is not provided, all clauses are shown.