구문 객체 바인딩
구문 객체 바인딩 (Syntax Object Bindings)
이 섹션은 구문 객체의 식별자들이 어떤 바인딩에 연결되는지 검사하고 비교하는 절차들을 다뤄요. 매크로를 작성할 때 식별자가 동일한 바인딩을 가리키는지, 지역·모듈·최상위 바인딩 중 어떤 것인지 판별하는 데 핵심적인 함수들이에요.
출처: Racket Reference
본문
(bound-identifier=? a-id b-id [phase-level]) → boolean?
a-id : syntax?
b-id : syntax?
phase-level : (or/c exact-integer? #f) = (syntax-local-phase-level)
식별자들이 phase-level이 나타내는 단계 수준의 적절한 표현식 문맥에 치환되었을 때 a-id가 b-id를 바인딩하면(또는 그 반대) #t, 아니면 #f를 반환해요. phase-level의 #f 값은 라벨 단계 수준에 대응해요.
예제:
> (define-syntax (check stx)
(syntax-case stx ()
[(_ x y)
(if (bound-identifier=? #'x #'y)
#'(let ([y 'wrong]) (let ([x 'binds]) y))
#'(let ([y 'no-binds]) (let ([x 'wrong]) y)))]))
> (check a a)
'binds
> (check a b)
'no-binds
> (define-syntax-rule (check-a x) (check a x))
> (check-a a)
'no-binds
(free-identifier=? a-id b-id [a-phase-level b-phase-level]) → boolean?
a-id : identifier?
b-id : identifier?
a-phase-level : (or/c exact-integer? #f) = (syntax-local-phase-level)
b-phase-level : (or/c exact-integer? #f) = a-phase-level
a-id와 b-id가 각각 a-phase-level과 b-phase-level이 나타내는 단계 수준에서 같은 지역 바인딩, 모듈 바인딩, 또는 최상위 바인딩에 접근하면—아마 rename 변환기를 통해서—#t를 반환해요. a-phase-level 또는 b-phase-level의 #f 값은 라벨 단계 수준에 대응해요.
"같은 모듈 바인딩"은 식별자들이 같은 원래 정의 위치를 가리킨다는 뜻이고, 반드시 같은 require나 provide 위치를 가리킨다는 뜻은 아니에요. require와 provide의 재명명이나 변환기의 rename 변환기 바인딩 때문에, 식별자들은 syntax-e로 서로 다른 결과를 반환할 수 있어요.
예제:
> (define-syntax (check stx)
(syntax-case stx ()
[(_ x)
(if (free-identifier=? #'car #'x)
#'(list 'same: x)
#'(list 'different: x))]))
> (check car)
'(same: #<procedure:car>)
> (check mcar)
'(different: #<procedure:mcar>)
> (let ([car list])
(check car))
'(different: #<procedure:list>)
> (require (rename-in racket/base [car kar]))
> (check kar)
'(same: #<procedure:car>)
(free-transformer-identifier=? a-id b-id) → boolean?
a-id : identifier?
b-id : identifier?
(free-identifier=? a-id b-id (add1 (syntax-local-phase-level)))과 같아요.
(free-template-identifier=? a-id b-id) → boolean?
a-id : identifier?
b-id : identifier?
(free-identifier=? a-id b-id (sub1 (syntax-local-phase-level)))과 같아요.
(free-label-identifier=? a-id b-id) → boolean?
a-id : identifier?
b-id : identifier?
(free-identifier=? a-id b-id #f)과 같아요.
(check-duplicate-identifier ids) → (or/c identifier? #f)
ids : (listof identifier?)
ids의 각 식별자를 목록의 다른 모든 식별자와 bound-identifier=?로 비교해요. 어떤 비교든 #t를 반환하면 중복 식별자 중 하나(중복인 ids의 첫 번째)를 반환하고, 아니면 #f를 반환해요.
(identifier-binding id-stx [phase-level top-level-symbol? exact-scopes?])
→ (or/c 'lexical #f
(list/c module-path-index? symbol?
module-path-index? symbol?
exact-nonnegative-integer?
phase+space-shift? phase+space?)
(list/c symbol?))
id-stx : identifier?
phase-level : (or/c exact-integer? #f) = (syntax-local-phase-level)
top-level-symbol? : any/c = #f
exact-scopes? : any/c = #f
phase-level이 나타내는 단계 수준(여기서 #f 값은 라벨 단계 수준에 대응)에서 id-stx의 바인딩에 따라 세 종류(top-level-symbol?이 #f일 때) 또는 네 종류(top-level-symbol?이 참일 때)의 값 중 하나를 반환해요.
-
id-stx가 지역 바인딩을 가지면 결과는'lexical이에요. -
id-stx가 모듈 바인딩을 가지면 결과는 일곱 항목의 목록이에요:(list from-mod from-sym nominal-from-mod nominal-from-sym from-phase import-phase+space-shift nominal-export-phase).from-mod는 정의 모듈을 나타내는 모듈 경로 인덱스예요(컴파일된 모듈과 참조 참고). 바인딩이id-stx를 둘러싼 모듈의 정의를 가리키면 "self" 모듈 경로 인덱스예요.from-sym은 원래 모듈의 해당 정의 위치에서 식별자 이름을 위한 심볼이에요. 이는 여러 이유로syntax->datum이 반환하는 지역 이름과 다를 수 있어요: 식별자가 가져올 때 재명명되었거나, 내보낼 때 재명명되었거나, 바인딩 위치가 매크로 호출로 만들어져 묵시적으로 재명명되었기 때문이에요. 마지막 경우에는 읽을 수 없는 심볼일 수 있고, 원래 소스 정의의 식별자에 대한syntax->datum결과와 다를 수 있어요.nominal-from-mod는id-stx주변 소스에 지역적으로 나타나는 바인딩 모듈을 나타내는 모듈 경로 인덱스예요(컴파일된 모듈과 참조 참고): 그 바인딩을 제공하기 위해id-stx의 문맥으로 요구되는 모듈을 나타내거나,id-stx를 둘러싼 모듈의 정의를 가리키는 바인딩에 대해from-mod와 같은 "self"예요.nominal-from-mod에서 어떤 가져온 식별자를 재내보내기 때문에from-mod와 다를 수 있어요. 같은 바인딩이 여러 방식으로 가져와지면 임의의 대표가 선택돼요.nominal-from-sym은id-stx주변 소스에 지역적으로 나타나는 바인딩 식별자를 위한 심볼이에요:nominal-from-mod가 내보내는 식별자 이름이거나,id-stx를 둘러싼 모듈 안 정의의 소스 식별자 심볼이에요.from-mod와nominal-from-mod가 같더라도 재명명provide때문에, 또는 매크로 확장이 도입한 정의 때문에from-sym과 다를 수 있어요.from-phase는 원래 단계를 나타내는 정확한 음이 아닌 정수예요. 예를 들어 정의가 for-syntax면 1이에요.import-phase+space-shift는 바인딩 가져오기가 정의나 일반require에서 온 것이면 0, for-syntax 가져오기에서 온 것이면 1, for-space 가져오기에서 온 것이면 단계와 공간 이름의 결합 등이에요.nominal-export-phase+space는 가져온 바인딩에 대해nominal-from-mod에서 내보낸 단계 수준과 바인딩 공간이거나,id-stx를 둘러싼 모듈의 바인딩에 대해 정의의 단계 수준이에요.
-
id-stx가 최상위 바인딩을 가지면 결과는(list top-sym)(단,top-level-symbol?이 참일 때)이에요.top-sym은 바인딩 정의가 매크로 호출로 만들어졌을 때syntax->datum이 반환하는 이름과 다를 수 있어요. -
id-stx가 최상위 바인딩을 가지면(top-level-symbol?이#f일 때) 또는id-stx가 바인딩되지 않았으면 결과는#f예요. 바인딩되지 않은 식별자는 보통 최상위 바인딩이 변수인 식별자와 똑같이 취급돼요.
id-stx가 rename 변환기에 바인딩되면, identifier-binding의 결과는 변환기 안의 식별자에 대한 것이므로, identifier-binding은 free-identifier=?와 일관돼요.
exact-scopes?가 참 값이면, id-stx의 바인딩이 정확히 id-stx의 스코프를 가질 때가 아니면 결과는 #f예요. 정확한 스코프 검사는 예를 들어 식별자가 특정 정의 문맥에 이미 바인딩되어 있는지 감지하는 데 유용해요.
변경 사항: base 패키지 6.6.0.4 버전에서 최상위 바인딩 정보를 보고하는
top-level-symbol?인자가 추가됐어요. 8.2.0.3 버전에서 단계 결과가 단계–공간 결합으로 일반화됐어요. 8.6.0.9 버전에서exact-scopes?인자가 추가됐어요.
(identifier-transformer-binding id-stx [rt-phase-level])
→ (or/c 'lexical #f
(listof module-path-index? symbol?
module-path-index? symbol?
exact-nonnegative-integer?
phase+space-shift? phase+space?))
id-stx : identifier?
rt-phase-level : (or/c exact-integer? #f) = (syntax-local-phase-level)
(identifier-binding id-stx (and rt-phase-level (add1 rt-phase-level)))과 같아요.
base 패키지 8.2.0.3 버전에서 단계 결과가 단계–공간 결합으로 일반화됐어요.
(identifier-template-binding id-stx)
→ (or/c 'lexical #f
(listof module-path-index? symbol?
module-path-index? symbol?
phase+space? phase+space-shift? phase+space?))
id-stx : identifier?
(identifier-binding id-stx (sub1 (syntax-local-phase-level)))과 같아요.
base 패키지 8.2.0.3 버전에서 단계 결과가 단계–공간 결합으로 일반화됐어요.
(identifier-label-binding id-stx)
→ (or/c 'lexical #f
(listof module-path-index? symbol?
module-path-index? symbol?
exact-nonnegative-integer?
phase+space-shift? phase+space?))
id-stx : identifier?
(identifier-binding id-stx #f)과 같아요.
base 패키지 8.2.0.3 버전에서 단계 결과가 단계–공간 결합으로 일반화됐어요.
(identifier-distinct-binding id-stx wrt-id-stx
[phase-level top-level-symbol?])
→ (or/c 'lexical #f
(list/c module-path-index? symbol?
module-path-index? symbol?
exact-nonnegative-integer?
phase+space-shift? phase+space?)
(list/c symbol?))
id-stx : identifier?
wrt-id-stx : identifier?
phase-level : (or/c exact-integer? #f) = (syntax-local-phase-level)
top-level-symbol? : any/c = #f
(identifier-binding id-stx phase-level top-level-symbol?)과 같지만, id-stx의 바인딩이 wrt-id-stx의 스코프의 부분집합인 스코프를 가지면 결과는 #f예요. 즉 id-stx와 wrt-id-stx가 같은 기호 이름을 가진다면, 바인딩이 wrt-id-stx에도 적용되지 않을 때만 id-stx에 대한 바인딩이 반환돼요.
base 패키지 8.3.0.8 버전에서 추가. 8.8.0.2 버전에서
top-level-symbol?인자가 추가됐어요.
(identifier-binding-symbol id-stx [phase-level]) → symbol?
id-stx : identifier?
phase-level : (or/c exact-integer? #f) = (syntax-local-phase-level)
identifier-binding과 같지만 바인딩에 대응하는 심볼을 만들어내요. 심볼 결과는 free-identifier=?인 어떤 식별자에 대해서도 같지만, free-identifier=?가 아닌 식별자에 대해서도 같을 수 있어요(즉 다른 심볼은 다른 바인딩을 의미하지만, 같은 심볼이 같은 바인딩을 의미하지는 않아요).
identifier-binding이 목록을 만들었을 때, 그 목록의 두 번째 요소가 identifier-binding-symbol이 만드는 결과예요.
(identifier-binding-portal-syntax id-stx [phase-level]) → (or/c #f syntax?)
id-stx : identifier?
phase-level : (or/c exact-integer? #f) = (syntax-local-phase-level)
id-stx가 phase-level에서 define-syntax나 #%require를 통해 포털 구문(portal syntax)에 바인딩되면 포털 구문 내용이 반환돼요. id-stx를 바인딩하는 모듈은 선언되어야 하지만, 관련 단계에서 인스턴스화될 필요는 없고, identifier-binding-portal-syntax는 그 모듈을 인스턴스화하지 않아요.
base 패키지 8.3.0.8 버전에서 추가.
(syntax-bound-symbols stx [phase-level exact-scopes?]) → (listof symbol?)
stx : syntax?
phase-level : (or/c exact-integer? #f) = (syntax-local-phase-level)
exact-scopes? : any/c = #f
(identifier-binding (datum->syntax stx sym) phase-level #f exact-scopes?)가 #f가 아닌 값을 만들 모든 인터닝된 심볼의 목록을 반환해요. 이 프로시저는 stx의 스코프 수에 결과 목록의 길이를 더한 것에 비례하는 시간이 걸려요.
base 패키지 8.6.0.6 버전에서 추가. 8.6.0.9 버전에서
exact-scopes?인자가 추가됐어요.
(syntax-bound-interned-scope-symbols stx [phase-level exact-scopes?])
→ (listof symbol?)
stx : syntax?
phase-level : (or/c exact-integer? #f) = (syntax-local-phase-level)
exact-scopes? : any/c = #f
(identifier-binding ((make-interned-syntax-introducer sym) stx) phase-level #f exact-scopes?)가 #f가 아닌 값을 만들 수 있는 인터닝된 스코프의 sym 이름 목록을 반환해요. 이 프로시저는 stx의 스코프 수에 결과 목록의 길이를 더한 것에 비례하는 시간이 걸려요.
base 패키지 8.13.0.8 버전에서 추가.
(syntax-bound-phases stx) → (listof (or/c exact-integer? #f))
stx : syntax?
(syntax-bound-symbols stx phase-level)가 비어 있지 않은 목록을 만들 수 있는 모든 단계 수준을 포함하는 목록을 반환해요.
예제:
> (syntax-bound-phases #'anything)
'(2 1 0)
> (require (for-meta 8 racket/base))
> (syntax-bound-phases #'anything)
'(9 8 2 1 0)
base 패키지 8.6.0.8 버전에서 추가.
더 알아보기
free-identifier=?,bound-identifier=?- 컴파일된 모듈과 참조(module path index)
datum->syntax,syntax-e