R6RS Scheme: 준인용
R6RS Scheme: 준인용
quasiquote 구문과 unquote, unquote-splicing 보조 구문을 설명해요. 일부만 알려진 구조를 갖는 리스트나 벡터를 만들 때 유용한 준인용의 문법, 의미, 문법 규칙을 다뤄요.
출처: 문서
본문
"백쿼트(backquote)" 또는 "준인용(quasiquote)" 표현식은 원하는 구조 중 일부만 미리 알려져 있을 때 리스트 또는 벡터 구조를 만드는 데 유용해요.
(quasiquote <qq template>) — syntax
문법: <qq template>은 이 항목 끝의 문법이 명시한 대로여야 해요.
의미: <qq template> 안에 unquote 또는 unquote-splicing 형식이 전혀 나타나지 않으면, (quasiquote <qq template>)의 평가 결과는 (quote <qq template>)의 평가 결과와 동등해요.
그러나 (unquote <expression> ...) 형식이 <qq template> 안에 나타나면, 그 <expression>들은 평가("unquote")되고 그 결과들이 unquote 형식 대신 구조에 삽입돼요.
(unquote-splicing <expression> ...) 형식이 <qq template> 안에 나타나면, 그 <expression>들은 리스트로 평가되어야 해요; 그 리스트들의 여는 괄호와 닫는 괄호가 "벗겨져서" 그 리스트들의 원소들이 unquote-splicing 형식 대신 삽입돼요.
어떤 unquote-splicing 형식이나 다중-피연산자 unquote 형식은 리스트 또는 벡터 <qq template> 안에서만 나타나야 해요.
4.3.5절에서 언급한 대로, (quasiquote <qq template>)는 `<qq template>` 로, (unquote <expression>)는 ,<expression>으로, (unquote-splicing <expression>)는 ,@<expression>으로 약어 표기될 수 있어요.
`(list ,(+ 1 2) 4) ⇒ (list 3 4)
(let ((name 'a)) `(list ,name ',name))
⇒ (list a (quote a))
`(a ,(+ 1 2) ,@(map abs '(4 -5 6)) b)
⇒ (a 3 4 5 6 b)
`((foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons)))
⇒ ((foo 7) . cons)
`#(10 5 ,(sqrt 4) ,@(map sqrt '(16 9)) 8)
⇒ #(10 5 2 4 3 8)
(let ((name 'foo))
`((unquote name name name)))
⇒ (foo foo foo)
(let ((name '(foo)))
`((unquote-splicing name name name)))
⇒ (foo foo foo)
(let ((q '((append x y) (sqrt 9))))
``(foo ,,@q))
⇒ `(foo (unquote (append x y) (sqrt 9)))
(let ((x '(2 3))
(y '(4 5)))
`(foo (unquote (append x y) (sqrt 9))))
⇒ (foo (2 3 4 5) 3)
준인용 형식들은 중첩될 수 있어요. 치환은 가장 바깥쪽 quasiquote와 같은 중첩 레벨에 나타나는 언쿼트된 성분들에 대해서만 이루어져요. 중첩 레벨은 각 연속적인 준인용 안에서 하나씩 증가하고, 각 언쿼트 안에서 하나씩 감소해요.
``(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)
⇒ (a `(b ,(+ 1 2) ,(foo 4 d) e) f)
(let ((name1 'x)
(name2 'y))
`(a `(b ,,name1 ,',name2 d) e))
⇒ (a `(b ,x ,'y d) e)
quasiquote 표현식은 표현식의 평가 중에 실행 시간에 만들어진 어떤 구조에 대해 새롭고 가변적인 객체 또는 리터럴 구조를 반환할 수 있어요. 재구성할 필요가 없는 부분은 항상 리터럴이에요. 따라서,
(let ((a 3)) `((1 2) ,a ,4 ,'five 6))
는 다음 표현식들 중 하나와 동등할 수 있어요:
'((1 2) 3 4 five 6)
(let ((a 3))
(cons '(1 2)
(cons a (cons 4 (cons 'five '(6))))))
그러나 다음 표현식과는 동등하지 않아요:
(let ((a 3)) (list (list 1 2) a 4 'five 6))
quasiquote, unquote, 또는 unquote-splicing 식별자 중 어떤 것이 위에서 설명한 대로가 아닌 방식으로 <qq template> 안의 위치에 나타나면 문법 위반이에요.
준인용 표현식에 대한 다음 문법은 문맥-자유(context-free)가 아니에요. 그것은 무한한 수의 생성 규칙을 만들기 위한 방법(recipe)으로 제시돼요. D = 1, 2, 3, ...에 대한 다음 규칙들의 복사본을 상상해보세요. D는 중첩 깊이를 추적해요.
<qq template> → <expression>
| <qq template1>
<qq template0> → <expression>
<quasiquotation D> → (quasiquote <qq template D>)
<qq template D> → <lexeme datum>
| <list qq template D>
| <vector qq template D>
| <unquotation D>
<list qq template D> → (<qq template or splice D> *)
| (<qq template or splice D>+ . <qq template D>)
| <quasiquotation D+1>
<vector qq template D> → #(<qq template or splice D> *)
<unquotation D> → (unquote <qq template D-1>)
<qq template or splice D> → <qq template D>
| <splicing unquotation D>
<splicing unquotation D> → (unquote-splicing <qq template D-1> *)
| (unquote <qq template D-1> *)
<quasiquotation>들에서, <list qq template D>는 때때로 <unquotation D> 또는 <splicing unquotation D>와 혼동될 수 있어요. <unquotation D> 또는 <splicing unquotation D>로서의 해석이 우선해요.