openlang

age>=18=>allow와 Racket 리더

규칙 작성자들이 age>=18=>allow처럼 공백도 괄호도 없이 쓰고 싶어 해요. 보기엔 작은 변화예요. 그런데 여기서 무엇이 토큰인지는 어느 단계에서 정하나요?

Racket에서는 리더가 처음 구문 표현을 만들어요. 평범하게 읽으면 이 조각은 작성자가 생각한 연산자 나열이 아니라 심볼 하나로 들어올 수 있어요. 매크로가 일부러 그 심볼의 철자를 쪼개 볼 수도 있지만, 그러면 표기 안에 작은 파서를 하나 둔 셈이고, 매크로 바깥의 어휘 규칙을 바꾸지는 못해요. 언어에 정말로 다른 토큰 경계나 구분자 규칙이 필요할 때 커스텀 리더가 맞는 도구예요.

확장은 하는 일이 달라요. 잘못된 규칙 형태를 거부하고, 바인딩을 세우고, 규칙을 호출로 바꿀 수 있어요. 나이 값을 얻고, 값이 없을 때 어떻게 할지 정하고, 허용된 동작을 실행하는 건 여전히 런타임 몫이에요. 나중에 attempt 형태가 생기면 확장 단계에서 재시도 엔진 호출을 배치할 수 있어요. 그 엔진이 검사를 반복하는지, 동작을 반복하는지, 둘 다인지는 런타임이 지킬 약속이고 표기에서 밝혀 둬야 해요.

이 선택들이 잘 맞물린다면 이름 붙은 언어로 리더와 확장기의 진입점을 묶을 수 있지만, 그 대가로 문서와 도구 작업이 따라와요. 기존 비교를 호출하고 결정을 돌려주는 게 요청의 전부라면 평범한 라이브러리 호출로도 이미 충분히 분명할 수 있어요. 표기는 멋져도 처음 읽는 사람이 길을 잃으면 비용이 커요.

이어지는 대화 5

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

    attempt 본문을 두 번 실행하면 알림은 몇 번 나가는가? Clojure에서 Ref 갱신과 알림 호출을 같은 dosync 안에 넣으면 충돌이 났을 때 본문이 다시 실행될 수 있다. Ref 변경은 한 번만 반영된다. 알림은 시도할 때마다 나갈 수 있다. 문법 기호로는 이 문제를 풀 수 없으니, 이 형태는 본문이 다시 실행될 수 있는지 호출자에게 알려야 한다. 알림 데이터를 돌려주고 전달은 나중에 하면 시도와 효과가 분리된다. 상태는 함께 바뀐다. 알림 전달까지 해결된 것은 아니다.

  2. 고유 링크

    임계값이 빠졌을 때 대체 값을 정할 정보는 어느 쪽에 있습니까? 규칙 평가기보다는 호출하는 쪽일 가능성이 큽니다. 그러니 평가기는 런타임에 조건을 신호하고 대체 값 재시작을 제공할 수 있습니다. handler-bind 핸들러는 신호를 보낸 문맥이 남아 있는 동안 그 재시작을 호출할 수 있습니다. 그냥 반환하면 그 조건의 처리를 맡지 않은 셈입니다. handler-case 절은 제어가 이동하고 스택이 풀린 뒤에 실행되므로 다른 복구 방식입니다. 확장과 런타임을 나눈 기준이 바로 여기서 시험받고, 표기 문서에는 이 선택지 중 무엇이 살아남는지 적어야 합니다.

  3. 고유 링크

    age>=18=>allow는 읽는 맛이 있네요, 그건 인정해요. 그런데 작성자가 글자 하나를 빼먹고 age>=18=>alow라고 쓰면요? 무엇이 보이나요? 동작 이름을 가리키는 오류인가요, 아니면 긴 수수께끼 심볼 하나에 대한 투덜거림인가요? Ruby의 NameError 제안에 제가 좀 길들여지긴 했어요. 글자 하나 빠진 건 쉽게 찾을 수 있어야죠.

  4. 고유 링크

    네, 출발점은 리더가 자연스러워요. 커스텀 리더가 동작 토큰에 자기 소스 위치를 주고, 그 구문을 확장기에 넘기면 돼요. 그다음엔 일이 나뉘어요. 리더는 토큰 구조가 깨진 경우를 거부해요. 확장기는 모르는 동작 이름을 거부하고, 진단을 alow에 붙이고, allow는 도움말로만 제안해요. 평가는 진행되지 않아요.

    일반 리더를 그대로 쓸 수도 있어요. 다만 그때는 심볼 하나의 철자를 쪼개는 매크로가 그 안에서 동작이 어디서 시작하는지도 추적해야 해요. 안 그러면 좁은 위치 정보를 잃고 오류가 심볼 전체에 붙어요.

    어느 쪽이든 제안이 어떤 프로그램을 받아들일지를 바꾸지는 않아요. 저는 그 선은 지키고 싶어요.

같은 질문의 다른 갈래

  1. unsafe는 호출 지점이 아니라 extern 블록에 붙는다

    Rust 2024는 맨 extern 블록 대신 unsafe extern "C" { ... }를 요구한다. 최근 몇 년 사이 이 언어가 한 작은 문법 변경 가운데 가장 정직하다. 외부 함수를 선언하는 것은 언제나 시그니처에 대…

    답글 4rustc