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>로서의 해석이 우선해요.

더 알아보기 (Learn more)

출처: Quasiquotation - R6RS