26.12 Управление итерациями

Iteration control clauses allow you to direct loop iteration. The loop keywords as, for, and repeat designate iteration control clauses.

Для управления итерациями используются выражения as, for и repeat.

Iteration control clauses differ with respect to the specification of termination conditions and the initialization and stepping of loop variables. Iteration clauses by themselves do not cause the Loop Facility to return values, but they can be used in conjunction with value-accumulation clauses to return values (see section 26.15).

Управление итерациями отличается от условий завершения цикла и инициализации и наращивания переменных цикла. Управление итерациями само по себе не выполняет возврат значение, но оно может использоваться в сочетании с выражениями накопления значения для возврата значений (смотрите раздел 26.15).

All variables are initialized in the loop prologue. The scope of the variable binding is lexical unless it is proclaimed special; thus, the variable can be accessed only by expressions that lie textually within the loop. Stepping assignments are made in the loop body before any other expressions are evaluated in the body.

Все переменные инициализируются в прологе цикла. Область видимости переменных лексическая, если только они не объявлены как специальные. Таким образом переменные доступны только в выражениях, которые текстово находятся в цикле. Наращивание переменных выполняется в теле цикла перед другими выражениями.

The variable argument in iteration control clauses can be a destructuring list. A destructuring list is a tree whose non-null atoms are symbols that can be assigned a value (see section 26.23.3).

На месте переменное может стоять список переменных для деструктуризации. Данный список представляет из себя дерево, в котором не-null атомы это символы, которые могут быть связаны со значениями (смотрите раздел 26.23.3).

The iteration control clauses for, as, and repeat must precede any other loop clauses except initially, with, and named, since they establish variable bindings. When iteration control clauses are used in a loop, termination tests in the loop body are evaluated before any other loop body code is executed.

Выражения для управления итерациями for, as и repeat должны быть указаны прежде других выражений за исключением initially, with и named, так как последние служат для создания переменных. При использовании выражений управления итерациями, проверка завершения выполняется перед самим телом цикла.

If you use multiple iteration clauses to control iteration, variable initialization and stepping occur sequentially by default. You can use the and construct to connect two or more iteration clauses when sequential binding and stepping are not necessary. The iteration behavior of clauses joined by and is analogous to the behavior of the Common Lisp macro do relative to do*.

Если вы используете несколько выражений для управления итерациями, по-умолчанию связывания и наращивания переменных выполняются последовательно. Если последовательное выполнение необязательно, вы можете объединить выражения с помощью конструкции and. Различия при неиспользовании и использовании конструкции and аналогичны различиям между do и do*

In the following example, the variable x is stepped before y is stepped; thus, the value of y reflects the updated value of x:

(loop for x from 1 to 9
      for y = nil then x
      collect (list x y))
    ((1 NIL) (2 2) (3 3) (4 4) (5 5) (6 6) (7 7) (8 8) (9 9))

In the following example, x and y are stepped in parallel:

(loop for x from 1 to 9
      and y = nil then x
      collect (list x y))
    ((1 NIL) (2 1) (3 2) (4 3) (5 4) (6 5) (7 6) (8 7) (9 8))

В следующем примере переменная x наращивается прежде чем y, таким образом y содержит новое значение x.

(loop for x from 1 to 9
      for y = nil then x
      collect (list x y))
    ((1 NIL) (2 2) (3 3) (4 4) (5 5) (6 6) (7 7) (8 8) (9 9))

В следующем примере переменные x и y наращиваются параллельно:

(loop for x from 1 to 9
      and y = nil then x
      collect (list x y))
    ((1 NIL) (2 1) (3 2) (4 3) (5 4) (6 5) (7 6) (8 7) (9 8))

The for and as clauses iterate by using one or more local loop variables that are initialized to some value and that can be modified or stepped after each iteration. For these clauses, iteration terminates when a local variable reaches some specified value or when some other loop clause terminates iteration. At each iteration, variables can be stepped by an increment or a decrement or can be assigned a new value by the evaluation of an expression. Destructuring can be used to assign initial values to variables during iteration.

Выражения for и as выполняют тело цикла для одной или нескольких переменных, которые вначале инициализируются некоторым значением, затем наращиваются после каждой итерации. Для этих выражений цикл завершается после того, как локальная переменная достигает последнего указанного значения, или срабатывает какое-либо другое завершающее выражение. На каждой итерации переменная может быть увеличена, уменьшена, или ей может быть связана с значением некоторого выражения. Для присваивания первоначальных значений может использоваться деструктуризация.

The for and as keywords are synonyms and may be used interchangeably. There are seven syntactic representations for these constructs. In each syntactic description, the data type of var can be specified by the optional type-spec argument. If var is a destructuring list, the data type specified by the type-spec argument must appropriately match the elements of the list (see sections 26.23.2 and 26.23.3).

Ключевые символы for и as являются синонимами, соответственно взаимозаменяемы. Для этих конструкций существует семь синтаксических представлений. В каждой из них для переменной var опционально можно задать тип type-spec. Если var является списком для деструктуризации, type-spec должен соответственно описывать элементы списка (смотрите разделы 26.23.2 и 26.23.3)

[Выражение цикла] for var [type-spec] [{from | downfrom | upfrom} expr1][{to | downto | upto | below | above} expr2][by expr3]

[Выражение цикла] as var [type-spec] [{from | downfrom | upfrom} expr1][{to | downto | upto | below | above} expr2][by expr3]

[This is the first of seven for/as syntaxes.—GLS]

The for or as construct iterates from the value specified by expr1 to the value specified by expr2 in increments or decrements denoted by expr3. Each expression is evaluated only once and must evaluate to a number.

The variable var is bound to the value of expr1 in the first iteration and is stepped by the value of expr3 in each succeeding iteration, or by 1 if expr3 is not provided.

The following loop keywords serve as valid prepositions within this syntax.

At least one of these prepositions must be used with this syntax.

In an iteration control clause, the for or as construct causes termination when the specified limit is reached. That is, iteration continues until the value var is stepped to the exclusive or inclusive limit specified by expr2. The range is exclusive if expr3 increases or decreases var to the value of expr2 without reaching that value; the loop keywords below and above provide exclusive limits. An inclusive limit allows var to attain the value of expr2; to, downto, and upto provide inclusive limits.

A common convention is to use for to introduce new iterations and as to introduce iterations that depend on a previous iteration specification. [However, loop does not enforce this convention, and some of the examples below violate it. De gustibus non disputandum est.—GLS]

Examples:

;;; Print some numbers.
(loop as i from 1 to 5
      do (print i)) ;Prints 5 lines
1
2
3
4
5
    NIL

;;; Print every third number.
(loop for i from 10 downto 1 by 3
      do (print i)) ;Prints 4 lines
10
7
4
1
    NIL

;;; Step incrementally from the default starting value.
(loop as i below 5
      do (print i)) ;Prints 5 lines
0
1
2
3
4
    NIL


[Выражение цикла] for var [type-spec] in expr1 [by step-fun]

[Выражение цикла] as var [type-spec] in expr1 [by step-fun]

[This is the second of seven for/as syntaxes.—GLS]

This construct iterates over the contents of a list. It checks for the end of the list as if using the Common Lisp function endp. The variable var is bound to the successive elements of the list expr1 before each iteration. At the end of each iteration, the function step-fun is called on the list and is expected to produce a successor list; the default value for step-fun is the cdr function.

The for or as construct causes termination when the end of the list is reached. The loop keywords in and by serve as valid prepositions in this syntax.

Examples:

;;; Print every item in a list.
(loop for item in ’(1 2 3 4 5) do (print item)) ;Prints 5 lines
1
2
3
4
5
    NIL

;;; Print every other item in a list.
(loop for item in ’(1 2 3 4 5) by #’cddr
      do (print item)) ;Prints 3 lines
1
3
5
    NIL

;;; Destructure items of a list, and sum the x values
;;; using fixnum arithmetic.
(loop for (item . x) (t . fixnum)
          in ’((A . 1) (B . 2) (C . 3))
      unless (eq item ’B) sum x)
    4


[Выражение цикла] for var [type-spec] on expr1 [by step-fun]

[Выражение цикла] as var [type-spec] on expr1 [by step-fun]

[This is the third of seven for/as syntaxes.—GLS]

This construct iterates over the contents of a list. It checks for the end of the list as if using the Common Lisp function endp. The variable var is bound to the successive tails of the list expr1. At the end of each iteration, the function step-fun is called on the list and is expected to produce a successor list; the default value for step-fun is the cdr function.

The loop keywords on and by serve as valid prepositions in this syntax. The for or as construct causes termination when the end of the list is reached.

Examples:

;;; Collect successive tails of a list.
(loop for sublist on ’(a b c d)
      collect sublist)
    ((A B C D) (B C D) (C D) (D))

;;; Print a list by using destructuring with the loop keyword ON.
(loop for (item) on ’(1 2 3)
      do (print item)) ;Prints 3 lines
1
2
3
    NIL

;;; Print items in a list without using destructuring.
(loop for item in ’(1 2 3)
      do (print item)) ;Prints 3 lines
1
2
3
    NIL


[Выражение цикла] for var [type-spec] = expr1 [then expr2]

[Выражение цикла] as var [type-spec] = expr1 [then expr2]

[This is the fourth of seven for/as syntaxes.—GLS]

This construct initializes the variable var by setting it to the result of evaluating expr1 on the first iteration, then setting it to the result of evaluating expr2 on the second and subsequent iterations. If expr2 is omitted, the construct uses expr1 on the second and subsequent iterations. When expr2 is omitted, the expanded code shows the following optimization:

;;; Sample original code:
(loop for x = expr1 then expr2 do (print x))

;;; The usual expansion:
(tagbody
      (setq x expr1)
  tag (print x)
      (setq x expr2)
      (go tag))

;;; The optimized expansion:
(tagbody
  tag (setq x expr1)
      (print x)
      (go tag))

The loop keywords = and then serve as valid prepositions in this syntax. This construct does not provide any termination conditions.

Example:

;;; Collect some numbers.
(loop for item = 1 then (+ item 10)
      repeat 5
      collect item)
    (1 11 21 31 41)


[Выражение цикла] for var [type-spec] across vector

[Выражение цикла] as var [type-spec] across vector

[This is the fifth of seven for/as syntaxes.—GLS]

This construct binds the variable var to the value of each element in the array vector.

The loop keyword across marks the array vector; across is used as a preposition in this syntax. Iteration stops when there are no more elements in the specified array that can be referenced.

Some implementations might use a [user-supplied—GLS] the special operator in the vector form to produce more efficient code.

Example:

(loop for char across (the simple-string (find-message port))
      do (write-char char stream))


[Выражение цикла] for var [type-spec] being {each | the}{hash-key | hash-keys | hash-value | hash-values}{in | of} hash-table [using ({hash-value | hash-key} other-var)]

[Выражение цикла] as var [type-spec] being {each | the}{hash-key | hash-keys | hash-value | hash-values}{in | of} hash-table [using ({hash-value | hash-key} other-var)]

[This is the sixth of seven for/as syntaxes.—GLS]

This construct iterates over the elements, keys, and values of a hash table. The variable var takes on the value of each hash key or hash value in the specified hash table.

The following loop keywords serve as valid prepositions within this syntax.

Iteration stops when there are no more hash keys or hash values to be referenced in the specified hash table.


[Выражение цикла] for var [type-spec] being {each | the}{symbol | present-symbol | external-symbol |symbols | present-symbols | external-symbols}{in | of} package

[Выражение цикла] as var [type-spec] being {each | the}{symbol | present-symbol | external-symbol |symbols | present-symbols | external-symbols}{in | of} package

[This is the last of seven for/as syntaxes.—GLS]

This construct iterates over the symbols in a package. The variable var takes on the value of each symbol in the specified package.

The following loop keywords serve as valid prepositions within this syntax.

Iteration stops when there are no more symbols to be referenced in the specified package.

Example:

(loop for x being each present-symbol of "COMMON-LISP-USER"
      do (print x)) ;Prints 7 lines in this example
COMMON-LISP-USER::IN
COMMON-LISP-USER::X
COMMON-LISP-USER::ALWAYS
COMMON-LISP-USER::FOO
COMMON-LISP-USER::Y
COMMON-LISP-USER::FOR
COMMON-LISP-USER::LUCID
    NIL


[Выражение цикла] repeat expr

The repeat construct causes iteration to terminate after a specified number of times. The loop body is executed n times, where n is the value of the expression expr. The expr argument is evaluated one time in the loop prologue. If the expression evaluates to zero or to a negative number, the loop body is not evaluated.

Конструкция repeat завершает цикл после указанного количества итераций. Тело цикла выполняется n раз, где n является значением выражения expr. Аргумент expr вычисляется единожды в прологе цикла. Если выражение возвращает ноль или отрицательное число, тело цикла не выполняется.

The clause repeat n is roughly equivalent to a clause such as

for internal-variable downfrom (- n 1) to 0

but, in some implementations, the repeat construct might be more efficient.

Выражение repeat n примерно похоже на выражение

for internal-variable downfrom (- n 1) to 0

но на некоторых реализациях repeat может быть более эффективна.

Examples:

(loop repeat 3 ;Prints 3 lines
      do (format t "What I say three times is true~%"))
What I say three times is true
What I say three times is true
What I say three times is true
    NIL

(loop repeat -15 ;Prints nothing
      do (format t "What you see is what you expect~%"))
    NIL

Примеры:

(loop repeat 3 ;Напечатает 3 строки
      do (format t "То, что я скажу три раза является истиной~%"))
То, что я скажу три раза является истиной
То, что я скажу три раза является истиной
То, что я скажу три раза является истиной
    NIL

(loop repeat -15 ;Ничего не напечатает
      do (format t "То что вы видите, это то, что вы ожидаете~%"))
    NIL