Common Lisp the Language, 2nd Edition

Next: Conditional Execution Up: Loop Previous: Value Accumulation

# 26.9. Variable Initializations

A local loop variable is one that exists only when the Loop Facility is invoked. At that time, the variables are declared and are initialized to some value. These local variables exist until loop iteration terminates, at which point they cease to exist. Implicitly variables are also established by iteration control clauses and the `into` preposition of accumulation clauses.

The loop keyword `with` designates a loop clause that allows you to declare and initialize variables that are local to a loop. The variables are initialized one time only; they can be initialized sequentially or in parallel.

By default, the `with` construct initializes variables sequentially; that is, one variable is assigned a value before the next expression is evaluated. However, by using the loop keyword `and` to join several `with` clauses, you can force initializations to occur in parallel; that is, all of the specified expressions are evaluated, and the results are bound to the respective variables simultaneously.

Use sequential binding for making the initialization of some variables depend on the values of previously bound variables. For example, suppose you want to bind the variables `a`, `b`, and `c` in sequence:

    (loop with a = 1
          with b = (+ a 2)
          with c = (+ b 3)
          with d = (+ c 4)
          return (list a b c d))
       => (1 3 6 10)

The execution of the preceding loop is equivalent to the execution of the following code:

    (let* ((a 1)
           (b (+ a 2))
           (c (+ b 3))
           (d (+ c 4)))
      (block nil
        (tagbody
          next-loop (return (list a b c d))
                    (go next-loop)
          end-loop)))

If you are not depending on the value of previously bound variables for the initialization of other local variables, you can use parallel bindings as follows:

    (loop with a = 1
           and b = 2
           and c = 3
           and d = 4
          return (list a b c d))
       => (1 2 3 4)

The execution of the preceding loop is equivalent to the execution of the following code:

    (let ((a 1)
          (b 2)
          (c 3)
          (d 4))
      (block nil
        (tagbody
          next-loop (return (list a b c))
                    (go next-loop)
          end-loop)))

[Loop Clause]
`with` var `[type-spec]` `[=` expr] {`and` var `[type-spec]` `[=` expr]}*

The `with` construct initializes variables that are local to a loop. The variables are initialized one time only.

If the optional type-spec argument is specified for any variable var, but there is no related expression expr to be evaluated, var is initialized to an appropriate default value for its data type. For example, for the data types `t`, `number`, and `float`, the default values are `nil`, `0`, and `0.0`, respectively. It is an error to specify a type-spec argument for var if the related expression returns a value that is not of the specified type. The optional `and` clause forces parallel rather than sequential initializations.

Examples:

    ;;; These bindings occur in sequence.
    (loop with a = 1
          with b = (+ a 2)
          with c = (+ b 3)
          with d = (+ c 4)
          return (list a b c d))
       => (1 3 6 10)

    ;;; These bindings occur in parallel.
    (setq a 5 b 10 c 1729)
    (loop with a = 1
           and b = (+ a 2)
           and c = (+ b 3)
           and d = (+ c 4)
          return (list a b c d))
       => (1 7 13 1733)

    ;;; This example shows a shorthand way to declare
    ;;; local variables that are of different types.
    (loop with (a b c) (float integer float)
          return (format nil "~A ~A ~A" a b c))
       => "0.0 0 0.0"

    ;;; This example shows a shorthand way to declare
    ;;; local variables that are of the same type.
    (loop with (a b c) float
          return (format nil "~A ~A ~A" a b c))
       => "0.0 0.0 0.0"

Next: Conditional Execution Up: Loop Previous: Value Accumulation