方案-引号和辅助语法

时间:2019-03-10 17:22:44

标签: scheme racket

由于某种原因,以下宏将无法使用引号引起作用。

*nbIsGranted

第二种情况为何失败,我感到很惊讶。

在两种情况下,都会打印以下调试信息。

(define-syntax expand
    (lambda (stx)
      (syntax-case stx (break)
        [(_ k () (ys ...)) (begin (println (syntax->datum #'(ys ...))) #'(ys ...))]
        [(_ k ((break) xs ...) (ys ...)) #'(expand k (xs ...) (ys ... (k (void))))]
        [(_ k ((es ...) xs ...) (ys ...)) #'(expand k (xs ...) (ys ... (expand k (es ...) ())))]
        [(_ k (a xs ...) (ys ...)) #'(expand k (xs ...) (ys ... a))])))

(define-syntax loop
    (syntax-rules ()
      [(_ e es ...)
       (call/cc (lambda (k)
                  (let l ()
                    (expand k (begin e es ...) ())
                    (l))))]))

(loop (list 1 (break)))
;; => works fine 

(loop (quasiquote (1 (unquote (break)))))
;; => break: unbound identifier in module in: break

请注意,在;; case 1 '(begin (expand k (list 1 (break)) ())) '(list 1 (k (void))) ;; case 2 '(begin (expand k `(1 ,(break)) ())) '`(expand k (1 ,(break)) ()) 扩展后的情况2的输出中,其余quasiquote并未扩展。

不确定为什么会这样。

谢谢

1 个答案:

答案 0 :(得分:2)

问题是宏扩展器无法扩展quotequasiquote下出现的宏调用。例如:

(define-syntax-rule (pipe) "|")

> (quote (pipe))
'(pipe)                ; not "|"
> (quasiquote (pipe))
'(pipe)                ; not "|"

这可以通过直接在编译时对语法对象进行递归来解决,而不是通过返回一个带有宏调用的语法对象来进行递归。

通常,翻译如下代码:

(define-syntax expand
  (lambda (stx)
    (syntax-case stx literals
      cases
      [pattern #'(.... (expand stuff) ...)]
      cases)))

输入如下代码:

(begin-for-syntax
  (define (expand stx)
    (syntax-case stx literals
      cases
      [pattern #`(.... #,(expand stuff) ...)]
      cases)))

在特定情况下,您可能希望expand是3参数函数,该函数在编译时完全运行并重复出现。

(begin-for-syntax
  (define (expand k xs ys)
    (with-syntax ([(ys ...) ys])
      (syntax-case xs (break)
        [()                (begin (println (syntax->datum #'(ys ...))) #'(ys ...))]
        [((break) xs ...)  (expand k #'(xs ...) #'(ys ... (k (void))))]
        [((es ...) xs ...) (expand k #'(xs ...) #`(ys ... #,(expand k #'(es ...) #'())))]
        [(a xs ...)        (expand k #'(xs ...) #'(ys ... a))]))))

然后您可以在loop宏的实现中调用此编译时函数:

(define-syntax loop
  (lambda (stx)
    (syntax-case stx ()
      [(_ e es ...)
       #`(call/cc (lambda (k)
                    (let l ()
                      #,(expand #'k #'(begin e es ...) #'())
                      (l))))])))

但是,这不是执行循环宏的最佳方法。

我希望上面的编译时函数可以帮助您理解宏的可能。但是,对于loop宏,则不需要它。 语法参数提供了一种更简单的方法。

(define-syntax-parameter break
  (lambda (stx) (raise-syntax-error #f "cannot be used outside of loop" stx)))

(define-syntax loop
  (syntax-rules ()
    [(_ e es ...)
     (call/cc (lambda (k)
                (define (break-function) (k (void)))
                (syntax-parameterize ([break (make-rename-transformer #'break-function)])
                  (let l ()
                    (begin e es ...)
                    (l)))))]))

实际上,像这样的loop宏是论文Keeping it Clean with Syntax Parameters section 4中使用的示例之一,称为forever,其中它称为中断语法参数abort