준인용: `quasiquote`, `unquote`, `unquote-splicing`
준인용: quasiquote, unquote, unquote-splicing
quasiquote는 인용(quote)과 달리 원하는 부분만 다시 평가(escape)해서 값을 채워 넣을 수 있는 문법이에요. unquote와 unquote-splicing을 이용해 인용된 데이터 속에 평가 결과를 끼워 넣지요.
출처: Racket Reference
본문
3.20 준인용: quasiquote, unquote, unquote-splicing
Racket 가이드의 "준인용: quasiquote와 `" 절에서 quasiquote를 소개해요.
syntax
(quasiquote datum)
datum에 (unquote expr) 또는 (unquote-splicing expr)이 포함되어 있지 않다면 quote datum과 동일해요. 그러나 (unquote expr) 폼은 인용에서 벗어나(escape)며, expr의 결과가 quasiquote 결과에서 (unquote expr) 폼이 있던 자리를 차지해요. (unquote-splicing expr)도 마찬가지로 벗어나지만, expr이 만들어 내는 리스트의 원소들이 여러 값으로 스플라이스(splice)되어 (unquote-splicing expr) 대신 들어가요.
unquote 또는 unquote-splicing 폼은 datum 안에서 다음의 이스케이프 위치에서만 인식돼요: 페어 안, 벡터 안, 박스 안, prefab 구조체의 이름 위치 다음의 필드, 그리고 해시 테이블의 값 위치(키 위치는 제외). 이런 이스케이프 위치는 임의의 깊이로 중첩될 수 있어요.
unquote-splicing 폼은 인용된 페어의 car로, 인용된 벡터의 원소로, 또는 인용된 prefab 구조체의 원소로 등장해야 해요. 페어의 경우, 해당 인용된 페어의 cdr이 비어 있다면 expr은 리스트를 만들 필요가 없으며, 그 결과가 인용된 페어 자리에 직접 사용돼요(append가 리스트가 아닌 마지막 인자를 받는 방식과 동일해요).
만약 unquote 또는 unquote-splicing이 quasiquote 안의 이스케이프 위치에 있지만 (unquote expr) 또는 (unquote-splicing expr) 형태가 아닌 다른 방식으로 나타나면, 문법 오류(syntax error)가 보고돼요.
예시:
> (quasiquote (0 1 2))
'(0 1 2)
> (quasiquote (0 (unquote (+ 1 2)) 4))
'(0 3 4)
> (quasiquote (0 (unquote-splicing (list 1 2)) 4))
'(0 1 2 4)
> (quasiquote (0 (unquote-splicing 1) 4))
unquote-splicing: contract violation
expected: list?
given: 1
> (quasiquote (0 (unquote-splicing 1)))
'(0 . 1)
quasiquote, unquote, unquote-splicing 폼은 각각 `(백틱), ,, ,@ 로 줄여서 쓸 수 있어요. Reading Quotes도 함께 보세요.
예시:
> `(0 1 2)
'(0 1 2)
> `(1 ,(+ 1 2) 4)
'(1 3 4)
> `#s(stuff 1 ,(+ 1 2) 4)
'#s(stuff 1 3 4)
> `#hash(("a" . ,(+ 1 2)))
'#hash(("a" . 3))
> `#hash((,(+ 1 2) . "a"))
'#hash((,(+ 1 2) . "a"))
> `(1 ,@(list 1 2) 4)
'(1 1 2 4)
> `#(1 ,@(list 1 2) 4)
'#(1 1 2 4)
원래 datum 안의 quasiquote 폼은 준인용의 단계(level)를 하나 올려요: quasiquote 폼 안에서는 각 unquote 또는 unquote-splicing이 보존되지만, 그보다 더 안쪽에 중첩된 unquote 또는 unquote-splicing은 벗어나요. quasiquote를 여러 번 중첩하면 벗어나기 위해 unquote 또는 unquote-splicing도 그만큼 여러 번 중첩해야 해요.
예시:
> `(1 `,(+ 1 ,(+ 2 3)) 4)
'(1 `,(+ 1 5) 4)
> `(1 ```,,@,,@(list (+ 1 2)) 4)
'(1 ```,,@,3 4)
quasiquote 폼은 unquote와 unquote-splicing 표현식을 분석하지 않고, 필요한 만큼만 새로운 cons 셀, 벡터, 박스를 할당해요. 예를 들어 다음에서
````(,1 2 3)
단 하나의 꼬리 (2 3)이 quasiquote 표현식을 평가할 때마다 재사용돼요. 새로운 데이터를 할당할 때 quasiquote 폼은 가변(mutable) 벡터, 가변 박스, 불변(immutable) 해시를 할당해요.
예시:
> (immutable? `#(,0))
#f
> (immutable? `#hash((a . ,0)))
#t
syntax
unquote
unquote가 이스케이프로 인식되는 quasiquote를 보세요. 표현식으로 사용된 unquote 폼은 문법 오류예요.
syntax
unquote-splicing
unquote-splicing이 이스케이프로 인식되는 quasiquote를 보세요. 표현식으로 사용된 unquote-splicing 폼은 문법 오류예요.