【问题标题】:In guile scheme, how to prevent renaming when calling macro from another macro?在 guile 方案中,如何防止从另一个宏调用宏时重命名?
【发布时间】:2020-04-08 23:50:56
【问题描述】:
; Having this definition that creates identifier `self'
(define-syntax alambda
  (lambda (stx)
    (syntax-case stx ()
      [(alambda lambda-list . body)
       (with-syntax ([name (datum->syntax #'alambda 'self)])
         #'(letrec ([name (lambda lambda-list . body)])
             name))])))

; I want to "compose" it with another macro
(define-syntax-rule [apply-alambda args argv . body]
  ((alambda args . body) . argv))

; But then it doesn't work (while alambda itself does)
(apply-alambda [x] [5] (if (= 0 x) 1 (* x (self (- x 1)))))
; => Unbound variable: self
; (expected 120)

如何防止apply-alambda重命名self


我尝试使用define-macro,但由于不同的原因,它也不起作用:

(defmacro apply-alambda [args argv . body]
  ((alambda args . body) . argv))
; => lambda: bad lambda in form (lambda args . body)

这里,我什至不知道出了什么问题

【问题讨论】:

    标签: macros scheme guile


    【解决方案1】:

    您的 alambda 宏不卫生,而且不卫生的宏不能很好地组合。基于已用于其他目的的子术语创建标识符的不卫生宏的组合尤其糟糕。一种解决方案是创建一个辅助宏,它将新标识符的“词法上下文”作为单独的参数。然后从中创建派生宏。

    (define-syntax alambda/lctx
      (lambda (stx)
        (syntax-case stx ()
          [(alambda lctx formals . body)
           (with-syntax ([name (datum->syntax #'lctx 'self)])
             #'(letrec ([name (lambda formals . body)])
                 name))])))
    
    (define-syntax alambda
      (lambda (stx)
        (syntax-case stx ()
          [(alambda formals . body)
           #'(alambda/lctx alambda formals . body)])))
    
    (define-syntax apply-alambda
      (lambda (stx)
        (syntax-case stx ()
          [(apply-alambda formals argv . body)
           #'((alambda/lctx apply-alambda formals . body) . argv)])))
    
    (apply-alambda [x] [5] (if (= 0 x) 1 (* x (self (- x 1)))))
    

    alambda 宏中,用于创建self 绑定器的词法上下文取自对宏本身的引用。该宏在对alambda/lctx 的调用中使该参数显式。与apply-alambda 类似——如果你想创建另一个扩展为apply-alambda 的宏,那么你同样应该创建一个apply-alambda/lctx 助手。

    (在 Racket 中,词法上下文不仅附加到标识符,还附加到列表结构(“括号”),不卫生的宏通常使用整个语法对象,如 (datum->syntax stx 'self)。这避免了需要一个单独的辅助宏。)

    注意:使用define-syntax-rule 定义alambdaapply-alambda 不起作用,因为它实际上并没有将标识符绑定到运算符位置。


    您可能很想使apply-alambda 调用alambda 并带有alambda 标识符,其词法上下文对应于apply-alambda 形式的使用,如下所示:

    (define-syntax bad-apply-alambda
      (lambda (stx)
        (syntax-case stx ()
          [(apply-alambda formals argv . body)
           (with-syntax ([alambda (datum->syntax #'apply-alambda 'alambda)])
             #'((alambda formals . body) . argv))])))
    

    这个版本是错误的。如果 alambda 在使用 bad-apply-alambda 的范围内未绑定(或绑定到错误的事物),则它的行为不正确。例如:

    (let ([alambda 5])
      (bad-apply-alambda [x] [5] (if (= 0 x) 1 (* x (self (- x 1))))))
    

    【讨论】:

      猜你喜欢
      • 2016-11-29
      • 2018-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-21
      • 2015-07-23
      • 1970-01-01
      相关资源
      最近更新 更多