CATCH 특수 연산자

CATCH 특수 연산자 (catch)

catch는 Common Lisp의 특수 연산자로, throw가 하는 비지역 제어 이동(non-local control transfer)의 목적지가 되어요. 태그(tag)로 서로를 찾아, 그동안 쌓인 평가 절차를 건너뛰고 원하는 지점으로 곧장 복귀하는 도구예요. block/return-from이 어휘적이라면, catch/throw는 동적으로 이어지는 제어 이동을 담당해요.

출처: CLHS: Special Operator CATCH

문법 (Syntax)

catch tag form* => result*

인자와 값 (Arguments and Values)

  • tag — catch 태그(catch tag)이며, 평가되어요.
  • forms — 암시적 progn이에요.
  • resultsform들이 정상적으로 끝나면 그들이 돌려준 값이고, tag로 throw가 발생하면 던져진 값들이에요.

설명 (Description)

catchthrow가 하는 비지역 제어 이동의 목적지로 쓰여요. 태그(tag)는 throw가 제어를 옮겨갈 catch를 찾는 데 쓰이죠. (catch 'foo form)(throw 'foo form)은 잡지만 (throw 'bar form)은 잡지 않아요.

catch의 실행 순서는 이래요.

  1. tag를 평가해요. 평가된 값이 그 catch의 이름 구실을 해요.
  2. form들을 암시적 progn으로 평가하고, throw가 없으면 마지막 form의 결과를 돌려줘요.
  3. form 중 하나를 실행하는 동안 throw가 발생하면, 그 throw의 태그 인자와 eq이고 가장 최근에 세워진 catch 폼으로 제어가 이동해요. 남은 form은 더 이상 평가되지 않아요.
  4. 결과를 돌려주기 직전에 catch가 세운 tag는 해제(disestablish)돼요.

form 중 하나를 실행하는 동안, catch 태그와 eq인 태그로 throw가 실행되면, throw가 지정한 값들이 그 태그를 가진 동적 최근 catch 폼의 결과로 반환돼요.

catchthrow의 메커니즘은 throwcatch의 어휘 범위 안에 있지 않아도 동작해요. 다만 throw는 대응 태그를 가진 catch 몸체의 평가(evaluation)라는 동적 지속(dynamic extent) 안에서 일어나야 해요.

예제 (Examples)

 (catch 'dummy-tag 1 2 (throw 'dummy-tag 3) 4) => 3
 (catch 'dummy-tag 1 2 3 4) => 4
 (defun throw-back (tag) (throw tag t)) => THROW-BACK
 (catch 'dummy-tag (throw-back 'dummy-tag) 2) => T
 ;; Contrast behavior of this example with corresponding example of BLOCK.
 (catch 'c
   (flet ((c1 () (throw 'c 1)))
     (catch 'c (c1) (print 'unreachable))
     2)) => 2

여기서 잠깐, block의 대응 예시와 대조해 볼게요. flet으로 정의한 함수 c1 안의 throw 'c 1안쪽 catch 'c에 잡혀요. throw는 어휘가 아니라 동적으로 가장 가까운 catch를 찾으니까요. 그래서 이 예시는 2를 반환하지만, block 버전은 1을 반환했죠. 어휘적 탈출과 동적 탈출의 차이가 정확히 여기서 갈라져요.

예외 상황 (Exceptional Situations)

throw가 자기한테 맞는 catch 태그가 없을 때 실행되면 control-error 타입의 오류가 신호(signal)돼요.

함께 보기 (See Also)

  • throw
  • Section 3.1 (Evaluation)

참고 (Notes)

태그는 관례상 기호(symbol)를 쓰지만, 어떤 객체든 쓸 수 있어요. 다만 비교가 eq로 이뤄지기 때문에 숫자는 쓰지 않는 게 좋아요.

catchblock과 달라요. catch 태그는 동적 유효 범위(dynamic scope)를 갖지만, block 이름은 어휘 유효 범위(lexical scope)를 갖죠.

더 알아보기 (Learn more)