prog, prog* — 변수 바인딩과 goto 기반 블록
prog, prog* — 변수 바인딩과 goto 기반 블록
오래된 구조적 프로그래밍 스타일처럼, 지역 변수를 묶고 return과 go로 제어를 옮기고 싶을 때가 있어요. prog와 prog*는 매크로로, 변수 바인딩·return·go라는 세 가지 동작을 한 폼에 합쳐 놓아요.
시그니처
prog ({var | (var [init-form])}*) declaration* {tag | statement}*
=> result*
prog* ({var | (var [init-form])}*) declaration* {tag | statement}*
=> result*
본문
인자와 값
var— 변수 이름이에요.init-form— 폼이에요.declaration—declare표현식이고, 평가되지 않아요.tag— go 태그이고, 평가되지 않아요.statement— compound form이고, 아래에서 설명하는 대로 평가돼요.results— 정상 반환(normal return) 이 일어나면nil, 명시적 반환(explicit return) 이 일어나면 전달된 값들이에요.
설명
prog와 prog*는 세 가지 서로 다른 동작을 수행해요: 지역 변수를 묶고, 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들이 해당 값에 병렬로(parallel) 묶여요. 어떤 var에 init-form이 주어지지 않으면 그 var는 nil로 묶여요.
prog의 몸통은 tagbody 폼처럼 실행돼요. go 문으로 제어를 tag로 옮길 수 있고, tag는 statement를 표시해요.
prog는 전체 폼 주위에 암묵적으로 nil이라는 이름의 블록을 만들기 때문에, 언제든 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
Affected By
없음.
Notes
prog는 block, let, tagbody로 다음과 같이 설명할 수 있어요:
(prog variable-list declaration . body)
== (block nil (let variable-list declaration (tagbody . body)))
더 알아보기
block— 명명된 블록let— 변수 바인딩tagbody— 태그 기반 제어 흐름go— 태그로 이동return— 블록에서 반환- Section 3.1 (Evaluation)