openlang

Common Lisp 핸들러가 그냥 반환하면 처리를 거절한 것이다

깔끔하게 줄였네요. 그래도 그 안에 무슨 약속이 들어 있는지는 봐야겠어요.

래퍼 매크로가 파서 둘레에 핸들러를 설치하고, 파서는 필드가 빠지면 컨디션을 시그널해요. 핸들러는 메모를 남기고 정상적으로 반환해요. Common Lisp에서 이렇게 반환하면 핸들러가 처리를 거절한 거예요. 파서가 회복했다는 뜻은 전혀 아니고, 시그널한다고 해서 바로 스택이 풀리는 것도 아니에요.

이제 그 핸들러를 호출자가 넘겨주는 걸로 바꿔 보죠. 거절할 수도 있고, 제어를 넘길 수도 있고, 쓸 수 있는 재시작을 호출할 수도 있어요. 래퍼의 겉모습이 깔끔하다고 믿기 전에 같은 시그널 하나를 두 경우에 다 따라가 봐요.

그럼 이 매크로가 실제로 약속하는 건 뭘까요? 재시작은 누가 세우고, 언제까지 쓸 수 있고, 시그널이 반환되면 파서는 무엇을 가정해도 되나요? 짧은 표기는 프로토콜을 알아보는 데는 좋아요. 약속 자체를 담아 두기에는 전개 결과가 좋은 자리가 아니에요.

이어지는 대화 3

서로의 근거를 따라
  1. 고유 링크

    재시작마다 허용하는 동작이 무엇이고, 그중 하나를 고를 만큼 아는 호출자는 누구입니까? 여기서는 Java와 비교해 볼 만합니다. 검사 예외 선언은 호출자에게 컴파일 시점의 의무를 지우지만, 실행 중에 생길 수 있는 실패를 전부 나열하지는 않습니다.

  2. 고유 링크

    로깅 핸들러는 첫 번째 예상으로 그대로 둬요. 그다음 하는 일만 바꿔서, 값을 공급하는 재시작을 호출하게 해 봐요. 래퍼가 두 경우를 모두 "처리됨"이라고 보고한다면 빠진 구분을 예제가 대신 찾아 준 거예요.

    이 두 흐름을 매크로 바로 옆에 적어 두면 좋겠어요. 각각 실행이 어디서 다시 이어지는지도요. 그렇게 보면 매번 전개해 보는 것보다 축약형이 오히려 읽기 쉬울 수 있어요. 처리를 거절하는 핸들러에 대한 설명도 같이 있다면요.

  3. 고유 링크

    Scheme은 이 질문을 두 프로시저로 나눠 두었고, 덕분에 래퍼가 무엇을 뜻하는지 말하기 쉬워진다. R7RS에서 with-exception-handler로 설치한 핸들러가 raise에서 반환하면, 핸들러의 동적 환경에서 이차 예외가 발생한다. raise-continuable이면 핸들러의 반환값이 그 호출의 값이 되고 파서는 계속 진행한다. 그러니 "핸들러가 반환했다"는 말은 파서가 어느 쪽을 썼느냐에 따라 뜻이 둘이고, 매크로 문서는 어느 쪽인지 밝혀야 한다. 6.11절은 짧으니 통째로 읽어 볼 만하다.

같은 질문의 다른 갈래

  1. 매크로 대부분이 const와 static이 됐다

    Nim은 매크로를 쓰기 쉽게 해 준다. 그게 문제다. macro에 손대기 전에 더 싼 도구부터 본다. const는 매크로를 돌리는 바로 그 VM이 컴파일 시점에 평가한다. 그래서 평범한 proc으로 만든 조회 테이블은 그냥…

    답글 4nim