프로시저 애플리케이션과 #%app
프로시저 애플리케이션과 #%app
Racket에서 함수를 호출하는 가장 일반적인 형태인 프로시저 애플리케이션(procedure application)이 내부적으로 어떻게 확장되는지 설명할게요. 같은 모양의 코드라도 #%app이라는 이름이 붙는 순간의 의미를 이해하면 매크로 확장을 다룰 때 유용해요.
출처: Racket Reference
본문
3.7 프로시저 애플리케이션과 #%app
The Racket Guide의 함수 호출 문서에서 프로시저 애플리케이션을 소개하고 있어요.
(proc-expr arg ...)
proc-expr가 트랜스포머 바인딩(확장 참고)을 가진 식별자가 아닐 때, 이 형태는 프로시저를 적용(apply)합니다.
좀 더 정확히는, 익스팬더가 이 폼을 (#%app proc-expr arg ...)로 변환합니다. 이때 #%app에게 원래 폼과 연결된 어휘적 문맥(즉, proc-expr와 그 인자들을 결합한 페어(pair))을 줍니다. 보통 이 페어의 어휘적 문맥은 다음에 설명할 프로시저 애플리케이션용 #%app을 가리키죠. 자세한 내용은 확장 단계도 참고하세요.
예시:
> (+ 1 2)
3
> ((lambda (x #:arg y) (list y x)) #:arg 2 1)
'(2 1)
#%app 폼
(#%app proc-expr arg ...)
프로시저를 적용합니다. 각 arg는 다음 중 하나입니다:
arg-expr
결과 값은 키워드가 아닌 인자(non-keyword argument)입니다.
keyword arg-expr
결과 값은 keyword를 사용하는 키워드 인자(keyword argument)입니다. 애플리케이션 안의 각 keyword는 서로 달라야 해요.
proc-expr와 arg-expr들은 왼쪽에서 오른쪽으로 순서대로 평가됩니다. proc-expr의 결과가 키워드가 아닌 arg-expr의 개수만큼 인자를 받는 프로시저이고, 애플리케이션에 있는 모든 키워드에 대한 인자를 받으며, 또 필수 키워드 기반 인자들이 모두 애플리케이션의 키워드들 안에 표현되어 있다면, 프로시저는 arg-expr들의 값으로 호출됩니다. 그렇지 않으면 exn:fail:contract 예외가 발생합니다.
프로시저 호출의 continuation은 애플리케이션 표현식의 continuation과 같아서, 프로시저의 결과가 곧 애플리케이션 표현식의 결과가 됩니다.
키워드 기반 인자들의 상대적 순서는 오직 arg-expr들의 평가 순서에만 영향을 줍니다. 인자들은 위치가 아니라 키워드에 기반해서 적용되는 프로시저의 인자 변수와 연결됩니다. 반면 나머지 arg-expr 값들은 애플리케이션 폼에서의 순서에 따라 변수와 연결됩니다.
익스팬더가 #%app 식별자를 어떻게 도입하는지에 대해서는 확장 단계를 참고하세요.
예시:
> (#%app + 1 2)
3
> (#%app (lambda (x #:arg y) (list y x)) #:arg 2 1)
'(2 1)
> (#%app cons)
cons: arity mismatch;
the expected number of arguments does not match the given
number
expected: 2
given: 0
#%plain-app 폼
(#%plain-app proc-expr arg-expr ...)
(#%plain-app)
#%app과 같지만 키워드 인자를 지원하지 않습니다. 특별한 경우로, (#%plain-app)는 '()를 만들어 냅니다.