26.19 Условное выполнение

The loop keywords if, when, and unless designate constructs that are useful when you want some loop clauses to operate under a specified condition.

Ключевые символы if, when и unless обозначают конструкцию, которая полезна, когда вы хотите выполнить некоторые действия только при выполнении некоторого условия.

If the specified condition is true, the succeeding loop clause is executed. If the specified condition is not true, the succeeding clause is skipped, and program control moves to the clause that follows the loop keyword else. If the specified condition is not true and no else clause is specified, the entire conditional construct is skipped. Several clauses can be connected into one compound clause with the loop keyword and. The end of the conditional clause can be marked with the keyword end.

Если условие истинно, выполняется следующее выражение. Если условие ложно, следующее выражение пропускается и выполнение переходит к выражению в ветке else. Если условие ложно и ветка else отсутствует, всё выражение просто пропускается. Несколько выражений могут объединены в одно с помощью and. Конец условного выражения можно обозначить символом end.

[Выражение цикла] if expr clause {and clause}*[else clause {and clause}*] [end]

[Выражение цикла] when expr clause {and clause}*[else clause {and clause}*] [end]

[Выражение цикла] unless expr clause {and clause}*[else clause {and clause}*] [end]

The constructs when and if allow conditional execution of loop clauses. These constructs are synonyms and can be used interchangeably.

Конструкции when и if выполняют действия в зависимости от условия. Эти конструкции являются синонимами и соответственно взаимозаменяемы.

If the value of the test expression expr is non-nil, the expression clause1 is evaluated. If the test expression evaluates to nil and an else construct is specified, the statements that follow the else are evaluated; otherwise, control passes to the next clause.

Если значение условия expr не-nil, выполняется выражение clause1. Если условие возвращает nil и указана ветка else выполняются выражения в этой ветке, иначе выполнение переходит к следующему выражению.

The unless construct is equivalent to when (not expr) and if (not expr). If the value of the test expression expr is nil, the expression clause1 is evaluated. If the test expression evaluates to non-nil and an else construct is specified, the statements that follow the else are evaluated; otherwise, control passes to the next clause. [Compare this to the macro unless, which does not allow an “else” part—or do I mean a “then” part?! Ugh. To prevent confusion, I strongly recommend as a matter of style that else not be used with unless loop clauses.—GLS]

Конструкция unless эквивалентна конструкциям when (not expr) и if (not expr). Если значение условия nil, выполняется выражение clause1. Если условие не-nil выполняется ветка else, иначе выполнение переходит к следующей конструкции.

The clause arguments must be either accumulation, unconditional, or conditional clauses (see section 26.6.3). Clauses that follow the test expression can be grouped by using the loop keyword and to produce a compound clause.

Аргументы clause должны быть или накоплением значения, безусловным или условным выполнением (смотрите раздел 26.6.3). Выражения, которые следуют после условия, могут группироваться с помощью and.

The loop keyword it can be used to refer to the result of the test expression in a clause. If multiple clauses are connected with and, the it construct must be used in the first clause in the block. Since it is a loop keyword, it may not be used as a local variable within a loop.

Для ссылки на результат условия может использоваться символ it. Если выражения были сгруппированы с помощью and, it должна использоваться только в первом выражении в блоке. Таким образом it не может использоваться в качестве локальной переменной внутри loop.

If when or if clauses are nested, each else is paired with the closest preceding when or if construct that has no associated else.

Если when или if вложены, каждый else относится к ближайшему предшествующему when или if, у которого ещё не было else.

The optional loop keyword end marks the end of the clause. If this keyword is not specified, the next loop keyword marks the end. You can use end to distinguish the scoping of compound clauses.

;;; Group conditional clauses into a block.
(loop for i in numbers-list
      when (oddp i)
        do (print i)
        and collect i into odd-numbers
        and do (terpri)
      else     ;I is even
        collect i into even-numbers
      finally
        (return (values odd-numbers even-numbers)))

;;; Collect numbers larger than 3.
(loop for i in ’(1 2 3 4 5 6)
      when (and (> i 3) i)
      collect it)     ;it refers to (and (> i 3) i)
    (4 5 6)

;;; Find a number in a list.
(loop for i in ’(1 2 3 4 5 6)
      when (and (> i 3) i)
      return it)
    4

;;; The preceding example is similar to the following one.
(loop for i in ’(1 2 3 4 5 6)
      thereis (and (> i 3) i))
    4

;;; An example of using UNLESS with ELSE (yuk). —GLS
(loop for turtle in teenage-mutant-ninja-turtles do
  (loop for x in ’(joker brainiac shredder krazy-kat)
        unless (evil x)
          do (eat (make-pizza :anchovies t))
        else unless (and (eq x ’shredder) (attacking-p x))
               do (cut turtle slack) ;When the evil Shredder attacks,
             else (fight turtle x))) ; those turtle boys don’t cut no slack

;;; Nest conditional clauses.
(loop for i in list
      when (numberp i)
        when (bignump i)
          collect i into big-numbers
        else     ;Not (bignump i)
          collect i into other-numbers
      else     ;Not (numberp i)
        when (symbolp i)
          collect i into symbol-list
        else     ;Not (symbolp i)
          (error "found a funny value in list ~S, value ~S~%"
                "list i))

;;; Without the END marker, the last AND would apply to the
;;; inner IF rather than the outer one.
(loop for x from 0 to 3
      do (print x)
      if (zerop (mod x 2))
        do (princ " a")
          and if (zerop (floor x 2))
                do (princ " b")
              end
          and do (princ " c"))

Конец можно обозначить необязательным символом end. Если этот символ не указан, конструкция заканчивается там, где начинается следующая, обозначенная символом. Вы можете использовать end для ограничения пространство составных выражений.

;;; Группирует условные выражение в блок.
(loop for i in numbers-list
      when (oddp i)
        do (print i)
        and collect i into odd-numbers
        and do (terpri)
      else     ;I is even
        collect i into even-numbers
      finally
        (return (values odd-numbers even-numbers)))

;;; Накапливает числа, большие чем 3.
(loop for i in ’(1 2 3 4 5 6)
      when (and (> i 3) i)
      collect it)     ;it ссылается на (and (> i 3) i)
    (4 5 6)

;;; Ищет числа в списке.
(loop for i in ’(1 2 3 4 5 6)
      when (and (> i 3) i)
      return it)
    4

;;; То же что и в предыдущем примере.
(loop for i in ’(1 2 3 4 5 6)
      thereis (and (> i 3) i))
    4

;;; Пример использования UNLESS с ELSE. —GLS
(loop for turtle in teenage-mutant-ninja-turtles do
  (loop for x in ’(joker brainiac shredder krazy-kat)
        unless (evil x)
          do (eat (make-pizza :anchovies t))
        else unless (and (eq x ’shredder) (attacking-p x))
               do (cut turtle slack) ;Когда злой Шрёдер атакует,
             else (fight turtle x))) ; эти черепашки-ниндзя дают ему отпор.

;;; Вложенные условные выражения.
(loop for i in list
      when (numberp i)
        when (bignump i)
          collect i into big-numbers
        else     ;Not (bignump i)
          collect i into other-numbers
      else     ;Not (numberp i)
        when (symbolp i)
          collect i into symbol-list
        else     ;Not (symbolp i)
          (error "нашёл интересное значение в списке ~S, значение ~S~%"
                "list i))

;;; Без маркера END последнее AND должно примениться к
;;; внутреннему IF, а не к внешнему.
(loop for x from 0 to 3
      do (print x)
      if (zerop (mod x 2))
        do (princ " a")
          and if (zerop (floor x 2))
                do (princ " b")
              end
          and do (princ " c"))