call/cc로 중첩 호출에서 빠져나와 바깥 호출에 결과를 반환할 수 있습니다. 탈출할 때 정리 코드를 실행하려면 dynamic-wind를 사용합니다.
call/cc가 넘겨주는 탈출 지점을 연속이라고 부릅니다.
각 예제의 코드 전체를 플레이그라운드에서 실행하세요. 일반적인 조건 선택에는 if나 cond를 쓰세요. 도우미 프로시저가 정상적으로 끝날 때는 결과를 그대로 반환하면 됩니다.
다음 식을 실행하기 전에 탈출하기
(call/cc (lambda (escape) (escape 'done) 'unreachable))결과
done실행은 세 단계로 이어집니다.
call/cc가 탈출 프로시저를 인자로 넘겨lambda를 호출합니다. 매개변수escape가 이 프로시저의 이름입니다.(escape 'done)이 람다에 남은 일을 중단하고 바깥call/cc가done을 반환하게 합니다.'unreachable식은 건너뜁니다. 실행은call/cc다음으로 이어집니다.
연속은 어떤 계산이 끝난 뒤 이어서 할 일입니다. 여기서 escape는 바깥 call/cc의 연속을 나타냅니다. 이를 호출하면 해당 call/cc 안쪽의 호출에서 빠져나옵니다. 이것을 상향 탈출이라고 합니다.
리스펙스에서는 바깥 call/cc가 실행 중일 때 한 번 탈출할 수 있습니다. 정리 코드가 시작되기 전에 탈출 프로시저는 사용된 상태가 됩니다. 정리 중이어도 이를 다시 호출하면 E340이 발생합니다.
진입과 본문과 정리 실행하기
(dynamic-wind
(lambda () (display "before "))
(lambda () (display "during "))
(lambda () (display "after")))출력
before during afterdynamic-wind는 인자 없이 호출할 프로시저 세 개를 받습니다.
| 프로시저 | 실행 시점 |
|---|---|
before | 진입할 때 |
thunk | before 다음에 본문 작업을 수행할 때 |
after | 본문이 끝나거나 오류 또는 탈출로 본문을 벗어날 때 |
thunk는 인자 없이 호출하는 프로시저를 가리킵니다. 정상적으로 끝나면 dynamic-wind는 본문 프로시저의 값들을 반환합니다. before와 after의 반환 값은 버립니다.
탈출할 때 정리 순서 따라가기
(write
(call/cc
(lambda (escape)
(dynamic-wind
(lambda () (display "before "))
(lambda ()
(display "during ")
(escape 'done)
(display "unreachable "))
(lambda () (display "after "))))))
(newline)출력
before during after done출력에서 실행 순서를 읽을 수 있습니다.
before가before를 출력합니다.- 본문 프로시저가
during을 출력하고escape를 호출합니다. - 본문에 남은
display는 건너뜁니다.after프로시저가after를 출력합니다. call/cc가done을 반환합니다. 바깥의write가 이를 출력하고newline이 줄을 바꿉니다.
정리할 일은 after에 두세요. 본문에서 오류나 탈출로 빠져나올 때도 실행됩니다. 중첩된 dynamic-wind 여러 개를 벗어나면 가장 안쪽부터 바깥쪽 순서로 정리합니다.
정리 중 새 오류가 나거나 다른 활성 탈출 프로시저를 호출하면 새 오류나 탈출이 진행 중이던 것을 대체합니다. 이미 쓴 escape를 정리 중 다시 호출하면 E340이 발생합니다.
실행 중인 호출에서만 탈출하기
(let ((saved #f))
(call/cc (lambda (escape) (set! saved escape) 'ready))
(saved 'late))진단
E340 escape continuation is no longer active여기서 call/cc는 ready를 정상 반환합니다. 마지막 식의 결과가 아니므로 이 값은 버립니다. 그 뒤 saved를 호출하면 바깥 call/cc가 끝났으므로 실패합니다. 한 번도 쓰지 않은 탈출 프로시저도 마찬가지입니다.
같은 규칙에 따라 끝난 계산에 다시 진입할 수도 없습니다. before는 진입할 때 실행되며 탈출로 다시 실행되지 않습니다. 일을 반복하려면 반복문이나 일반 프로시저 호출을 사용하세요.
리스펙스는 평가기 안에서 오류와 탈출 신호를 바깥 호출로 전달합니다. 이 신호는 호출 애플리케이션의 언어가 쓰는 예외나 연속과 구별됩니다.