loop
loop Macro
Syntax:
The “simple” loop form:
loop {compound-form}* → {result}*
The “extended” loop form:
loop [↓name-clause] {↓variable-clause}* {↓main-clause}* → {result}*
name-clause::=named name
variable-clause::=↓with-clause | ↓initial-final | ↓for-as-clause
with-clause::=with var1 [type-spec] [= form1] {and var2 [type-spec] [= form2]}*
main-clause::=↓unconditional | ↓accumulation | ↓conditional | ↓termination-test | ↓initial-final initial-final::=initially {compound-form}+| finally {compound-form}+
unconditional::={do | doing} {compound-form}+| return {form | it}
accumulation::=↓list-accumulation | ↓numeric-accumulation
list-accumulation::={collect | collecting | append | appending | nconc | nconcing} {form | it} [into simple-var]
loopnumeric-accumulation::=*{*count | counting | sum | summing |
maximize | maximizing | minimize | minimizing*} {form |* it}
[into simple-var] [type-spec]
conditional::=*{if | when | unless} form ↓selectable-clause {*and ↓selectable-clause}*
[else *↓selectable-clause {*and ↓selectable-clause}*]
[end]
selectable-clause::=↓unconditional | ↓accumulation | ↓conditional
termination-test::=while form | until form | repeat form | always form | never form | thereis form for-as-clause::=*{for | as} ↓for-as-subclause {*and ↓for-as-subclause}*
for-as-subclause::=↓for-as-arithmetic | ↓for-as-in-list | ↓for-as-on-list | ↓for-as-equals-then | ↓for-as-across | ↓for-as-hash | ↓for-as-package
for-as-arithmetic::=var [type-spec] ↓for-as-arithmetic-subclause
for-as-arithmetic-subclause::=↓arithmetic-up | ↓arithmetic-downto | ↓arithmetic-downfrom arithmetic-up::=[[ {from | upfrom} form1 | {to | upto | below} form2 | by form3 ]]+
arithmetic-downto::=[[ {from form1}1| {{downto | above} form2}1| by form3 ]]
arithmetic-downfrom::=[[ {downfrom form1}1| {to | downto | above} form2 | by form3 ]] for-as-in-list::=var [type-spec] in form1 [by step-fun]
for-as-on-list::=var [type-spec] on form1 [by step-fun]
for-as-equals-then::=var [type-spec] = form1 [then form2]
for-as-across::=var [type-spec] across vector
for-as-hash::=var [type-spec] being {each | the}
{{hash-key | hash-keys} {in | of} hash-table
[using (hash-value other-var)] |
{hash-value | hash-values} {in | of} hash-table
[using (hash-key other-var)]}
loopfor-as-package::=var [type-spec] being {each | the}
*{*symbol | symbols |
present-symbol | present-symbols |
external-symbol | external-symbols*}*
[{in | of} package]
type-spec::=↓simple-type-spec | ↓destructured-type-spec
simple-type-spec::=fixnum | float | t | nil
destructured-type-spec::=of-type d-type-spec
d-type-spec::=type-specifier | (d-type-spec . d-type-spec)
var::=↓d-var-spec
var1::=↓d-var-spec
var2::=↓d-var-spec
other-var::=↓d-var-spec
d-var-spec::=simple-var | nil | (↓d-var-spec . ↓d-var-spec)
Arguments and Values:
compound-form—a compound form.
name—a symbol.
simple-var—a symbol (a variable name).
form, form1, form2, form3—a form.
step-fun—a form that evaluates to a function of one argument.
vector—a form that evaluates to a vector .
hash-table—a form that evaluates to a hash table.
package—a form that evaluates to a package designator .
type-specifier—a type specifier . This might be either an atomic type specifier or a compound type specifier , which introduces some additional complications to proper parsing in the face of destructuring; for further information, see Section 6.1.1.7 (Destructuring).
result—an object.
loopDescription:
For details, see Section 6.1 (The LOOP Facility).
Examples:
;; An example of the simple form of LOOP.
(defun sqrt-advisor ()
(loop (format t "~&Number: ")
(let ((n (parse-integer (read-line) :junk-allowed t)))
(when (not n) (return))
(format t "~&The square root of ~D is ~D.~%" n (sqrt n)))))
→ SQRT-ADVISOR
(sqrt-advisor)
▷ Number: 5←
▷ The square root of 5 is 2.236068.
▷ Number: 4←
▷ The square root of 4 is 2.
▷ Number: done←
→ NIL
;; An example of the extended form of LOOP.
(defun square-advisor ()
(loop as n = (progn (format t "~&Number: ")
(parse-integer (read-line) :junk-allowed t))
while n
do (format t "~&The square of ~D is ~D.~%" n (\* n n))))
→ SQUARE-ADVISOR
(square-advisor)
▷ Number: 4←
▷ The square of 4 is 16.
▷ Number: 23←
▷ The square of 23 is 529.
▷ Number: done←
→ NIL
;; Another example of the extended form of LOOP.
(loop for n from 1 to 10
when (oddp n)
collect n)
→ (1 3 5 7 9)
See Also:
do, dolist, dotimes, return, go, throw, Section 6.1.1.7 (Destructuring)
Notes:
Except that loop-finish cannot be used within a simple loop form, a simple loop form is related to an extended loop form in the following way:
(loop {compound-form}*) ≡ (loop do {compound-form}*)
Expanded Reference: loop
Looping over a list
(let ((lst (list 5 4 3 "b" "a")))
(loop for el in lst
do (print el)))
5
4
3
"b"
"a"
NIL
Looping and declaring lexical variables with
Note the usage of the word with
below. with
will be executed once at the beginning of the loop. See below the usage of for
which updates the binding on each run of the loop.
(loop for x below 50
with i = 0
when (and (< i 10)
(not (evenp x)))
do (print x)
(incf i))
1
3
5
7
9
11
13
15
17
19
NIL
This is similar to the alternative of wrapping the loop
form in a let
form.
(let ((i 0))
(loop for x below 50
when (and (< i 10)
(not (evenp x)))
do (print x)
(incf i)))
Loop using with
keyword to declare variables that depend on each other
The with
form will not have the value of any preceeding variable bound with for
at the beginning of the loop. However variables bound with another with
will be available.
(loop for x in (list 1 2 3)
with a = 1
with b = (* 8 a)
do (print b))
8
8
8
NIL
However using the x
variable would not work:
(loop for x in (list 1 2 3)
with a = 1
with b = (* 8 x)
do (print b))
Value of X in (* 8 X) is NIL, not a NUMBER.
[Condition of type SIMPLE-TYPE-ERROR]
Note: The preferred style when using both the with
and for
keywords is to write the with
clauses first:
(loop with a = 2
for y in (list 1 2 3)
do (print y))
Loop with lexical variables and updates
Notice the usage of the for
keyword which indicates the binding should be updated on each run of the loop.
(loop for x in (list 1 2 3 4)
for y = (* x 2)
do (print y))
2
4
6
8
NIL
The y
variable will be updated on each run based on the given form (* x 2)
Looping over a Hash Table
(let ((given-ht (serapeum:dict "a" 1 "b" 2)))
(loop for key being each hash-key of given-ht
using (hash-value value)
do (format t "~A: ~A ~%" key value)))
a: 1
b: 2
NIL
(let ((given-ht (serapeum:dict "a" 1 "b" 2)))
(loop for value being each hash-value of given-ht
do (format t "~A~%" value)))
1
2
NIL
(let ((given-ht (serapeum:dict "a" 1 "b" 2)))
(loop for key being each hash-key of given-ht
do (format t "~A~%" key)))
a
b
NIL