실행 도중 빠져나오기

call/cc로 중첩 호출에서 한 번 빠져나오고 dynamic-wind의 정리 순서를 따라갑니다.

call/cc로 중첩 호출에서 빠져나와 바깥 호출에 결과를 반환할 수 있습니다. 탈출할 때 정리 코드를 실행하려면 dynamic-wind를 사용합니다. call/cc가 넘겨주는 탈출 지점을 연속이라고 부릅니다.

각 예제의 코드 전체를 플레이그라운드에서 실행하세요. 일반적인 조건 선택에는 if나 cond를 쓰세요. 도우미 프로시저가 정상적으로 끝날 때는 결과를 그대로 반환하면 됩니다.

다음 식을 실행하기 전에 탈출하기

LISPEX
(call/cc (lambda (escape) (escape 'done) 'unreachable))

결과

출력
done

실행은 세 단계로 이어집니다.

  1. call/cc가 탈출 프로시저를 인자로 넘겨 lambda를 호출합니다. 매개변수 escape가 이 프로시저의 이름입니다.
  2. (escape 'done)이 람다에 남은 일을 중단하고 바깥 call/cc가 done을 반환하게 합니다.
  3. 'unreachable 식은 건너뜁니다. 실행은 call/cc 다음으로 이어집니다.

연속은 어떤 계산이 끝난 뒤 이어서 할 일입니다. 여기서 escape는 바깥 call/cc의 연속을 나타냅니다. 이를 호출하면 해당 call/cc 안쪽의 호출에서 빠져나옵니다. 이것을 상향 탈출이라고 합니다.

리스펙스에서는 바깥 call/cc가 실행 중일 때 한 번 탈출할 수 있습니다. 정리 코드가 시작되기 전에 탈출 프로시저는 사용된 상태가 됩니다. 정리 중이어도 이를 다시 호출하면 E340이 발생합니다.

진입과 본문과 정리 실행하기

LISPEX
(dynamic-wind
  (lambda () (display "before "))
  (lambda () (display "during "))
  (lambda () (display "after")))

출력

출력
before during after

dynamic-wind는 인자 없이 호출할 프로시저 세 개를 받습니다.

프로시저실행 시점
before진입할 때
thunkbefore 다음에 본문 작업을 수행할 때
after본문이 끝나거나 오류 또는 탈출로 본문을 벗어날 때

thunk는 인자 없이 호출하는 프로시저를 가리킵니다. 정상적으로 끝나면 dynamic-wind는 본문 프로시저의 값들을 반환합니다. before와 after의 반환 값은 버립니다.

탈출할 때 정리 순서 따라가기

LISPEX
(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

출력에서 실행 순서를 읽을 수 있습니다.

  1. before가 before 를 출력합니다.
  2. 본문 프로시저가 during 을 출력하고 escape를 호출합니다.
  3. 본문에 남은 display는 건너뜁니다. after 프로시저가 after 를 출력합니다.
  4. call/cc가 done을 반환합니다. 바깥의 write가 이를 출력하고 newline이 줄을 바꿉니다.

정리할 일은 after에 두세요. 본문에서 오류나 탈출로 빠져나올 때도 실행됩니다. 중첩된 dynamic-wind 여러 개를 벗어나면 가장 안쪽부터 바깥쪽 순서로 정리합니다.

정리 중 새 오류가 나거나 다른 활성 탈출 프로시저를 호출하면 새 오류나 탈출이 진행 중이던 것을 대체합니다. 이미 쓴 escape를 정리 중 다시 호출하면 E340이 발생합니다.

실행 중인 호출에서만 탈출하기

LISPEX
(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는 진입할 때 실행되며 탈출로 다시 실행되지 않습니다. 일을 반복하려면 반복문이나 일반 프로시저 호출을 사용하세요.

리스펙스는 평가기 안에서 오류와 탈출 신호를 바깥 호출로 전달합니다. 이 신호는 호출 애플리케이션의 언어가 쓰는 예외나 연속과 구별됩니다.

일반적인 조건 선택은 조건식에서, 오류 읽는 법은 진단에서 확인하세요.