실행으로 확인하기
(let* ((x 6) (y (+ x 1))) (* x y))관측 결과
42let*는 먼저 x를 묶고 그 값으로 y를 계산합니다. 리스펙스는 실행 전에 이 바인딩을 중첩된 let 형식으로 바꿉니다.
(let ((x 6))
(let ((y (+ x 1)))
(* x y)))관측 결과
42플레이그라운드에서 두 예제를 각각 실행해 보세요. 모두 42를 반환합니다.
정규화가 하는 일
형식은 프로그램을 이루는 문법 단위입니다. 파생 형식은 리스펙스가 핵심 형식으로 바꾸는 축약 문법입니다. 이 변환을 정규화라고 합니다.
정규화는 프로그램의 이름과 충돌하지 않는 새 내부 이름을 만듭니다. 숨은 내장 연산도 사용합니다. 예를 들어 사용자가 eqv?를 정의해도 case의 데이터 비교 방식은 바뀌지 않습니다. 이름이 섞여 뜻이 바뀌는 일을 막는 이 성질을 위생성이라고 합니다.
정규화는 평가 순서와 꼬리 위치, 소스에 연결된 진단을 보존합니다. 꼬리 위치는 현재 호출에서 더 할 일 없이 식의 결과를 바로 반환하는 자리입니다.
줄여 쓴 형식이 바뀌는 방식
| 줄여 쓴 형식 | 핵심 형식으로 바꾸는 방법 | 평가 규칙 |
|---|---|---|
cond / case | 새 임시 이름을 쓴 중첩 if. case는 숨은 eqv? 사용 | 각 절의 마지막 식이 가진 꼬리 위치를 보존. cond =>는 거부 |
and / or | 결과가 정해지면 멈추는 중첩 if | 마지막 피연산자의 꼬리 위치를 보존 |
when / unless | if에 본문용 begin 또는 인자 없는 values를 결합 | 본문을 건너뛰면 값 0개를 반환 |
이름 있는 let / do | 이름 충돌을 막은 letrec 반복 | 재귀 호출이 꼬리 위치에 있음 |
quasiquote | quote와 숨은 데이터 생성 연산 | 준인용 밖 단독 unquote는 정적 E1xx 오류 |
case에서 datum은 수나 심볼, 리스트처럼 하나로 읽는 데이터입니다. 각 절의 데이터를 식으로 평가하지 않고 eqv?로 비교합니다.
guard는 전용 핵심 형식으로 잡을 수 있는 오류를 처리합니다. 문법과 처리 규칙도 내장되어 있습니다.
내장 문법 규칙
리스펙스는 평가 전에 내장 변환 규칙을 적용합니다. define-syntax와 구문 객체, 임의의 사용자 정의 확장은 거부합니다. 실행 중 건너뛸 분기도 문법 검사를 받습니다.
다음으로
변환 결과의 문법은 기본 문법 형식에서 찾아보세요. if와 cond, case를 고르는 방법은 조건 쓰기에서 설명합니다.