Macro PROG, PROG*
prog ({var | (var [init-form])}*) declaration* {tag | statement}*
=> result*
prog* ({var | (var [init-form])}*) declaration* {tag | statement}*
=> result*
var - 変数名
init-form - フォーム
declaration - 宣言式。評価されません。
tag - goタグ。評価されません。
statement - compound-form。下記の説明に従って評価されます。
result - 通常の返却のときはnil、 そうではなくreturn-fromによる明示的な返却のときは転送された返却値。
progとprog*によって 3つの異なった操作が実行されます。 それは、ローカル変数の束縛と、 return構文の使用の許可と、 go構文の使用の許可です。 典型的なprogの見た目は次のようになります。
(prog (var1 var2 (var3 init-form-3) var4 (var5 init-form-5))
declaration*
statement1
tag1
statement2
statement3
statement4
tag2
statement5
...
)progでは、 最初に各init-formが指定された順に評価されます。 そのあとvarが対応する値と並列に束縛されます。 もしvarに対してinit-formが存在しないとき、 そのvarにはnilが束縛されます。
progのボディ部は それがtagbodyフォームであるかのように実行されます。 go構文はtagへ制御を移すときに使うことができます。 tagはstatementにラベル付けされます。
progは暗黙に、progフォーム全体を囲うようにして、 nilというblockが確立しており、 returnを使ってprogフォームからいつでも退出できます。
prog*とprogの違いは、 prog*はvarの束縛と初期化は連続的に行われ、 各変数のinit-formの値は、以前の変数の値によって使用することができます。
(prog* ((y z) (x (car y)))
(return x))上記はzの値のcarを返却します。
(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 これは下記に示すように、より明確に達成できます。
(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, 3.1. 評価
progは、blockとletとtagbodyの語を用いて 下記のように説明することができます。
(prog variable-list declaration . body)
== (block nil (let variable-list declaration (tagbody . body)))