var—variable name.
init-form—a form.
declaration—a declare expression; not evaluated.
tag—a go tag; not evaluated.
statement—a compound form; evaluated as described below.
results—nil
if a normal return occurs,
or else, if an explicit return occurs, the values that were transferred.
Three distinct operations are performed by prog
and
prog*
:
they bind local variables,
they permit use of the return
statement, and they permit use of the go
statement.
A typical prog
looks like this:
(prog (var1 var2 (var3 init-form-3) var4 (var5 init-form-5)) {declaration}* statement1 tag1 statement2 statement3 statement4 tag2 statement5 ... )
For prog
,
init-forms are evaluated first, in the order in which they are
supplied. The vars are then bound to the corresponding values in
parallel. If no init-form
is supplied for a given var,
that var is bound to nil
.
The body of prog
is executed as if it were a tagbody
form;
the go
statement can be used to transfer control
to a tag.
Tags label statements.
prog
implicitly establishes a block
named nil
around
the entire prog
form, so that return
can be used
at any time to exit from the prog
form.
The difference between prog*
and prog
is that
in prog*
the binding and initialization of the vars
is done sequentially, so that the init-form for each
one can use the values of previous ones.
(prog* ((y z) (x (car y))) (return x))
returns the car of the value of z
.
(setq a 1) → 1 (prog ((a 2) (b a)) (return (if (= a b) '= '/=))) → /= (prog* ((a 2) (b a)) (return (if (= a b) '= '/=))) → = (prog () 'no-return-value) → NIL
(defun king-of-confusion (w)
"Take a cons of two lists and make a list of conses.
Think of this function as being like a zipper."
(prog (x y z) ;Initialize x, y, z to NIL
(setq y (car w) z (cdr w))
loop
(cond ((null y) (return x))
((null z) (go err)))
rejoin
(setq x (cons (cons (car y) (car z)) x))
(setq y (cdr y) z (cdr z))
(go loop)
err
(cerror "Will self-pair extraneous items"
"Mismatch - gleep! ~S" y)
(setq z y)
(go rejoin))) → KING-OF-CONFUSION
This can be accomplished more perspicuously as follows:
(defun prince-of-clarity (w)
"Take a cons of two lists and make a list of conses.
Think of this function as being like a zipper."
(do ((y (car w) (cdr y))
(z (cdr w) (cdr z))
(x '() (cons (cons (car y) (car z)) x)))
((null y) x)
(when (null z)
(cerror "Will self-pair extraneous items"
"Mismatch - gleep! ~S" y)
(setq z y)))) → PRINCE-OF-CLARITY
block, let, tagbody, go, return, Section 3.1 (Evaluation)
prog
can be explained in terms of
block
, let
, and tagbody
as
follows:
(prog variable-list declaration . body) ≡ (block nil (let variable-list declaration (tagbody . body)))