Common Lisp the Language, 2nd Edition


next up previous contents index
Next: Conditional Execution Up: Loop Previous: Value Accumulation

26.9. Variable Initializations

change_begin
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"


change_end



next up previous contents index
Next: Conditional Execution Up: Loop Previous: Value Accumulation


AI.Repository@cs.cmu.edu