首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >动态绑定函数体中的空闲标识符

动态绑定函数体中的空闲标识符
EN

Stack Overflow用户
提问于 2016-12-14 10:09:09
回答 1查看 322关注 0票数 5

考虑一种非常简单的参与者语言,其中一个参与者定义了一些本地状态和一些方法,这些方法可以通过向参与者发送消息来调用。在其实现中,可以将参与者的一种方法转换为一个函数,该函数定义该方法的形式参数并接受该参与者的当前本地状态。调用该方法将返回新的本地状态。

约束身体中的形式参数是没有问题的,但是约束局部状态似乎更困难。在下面代码末尾的示例中,在save方法的主体中,a将保持未绑定,尽管a (一个不同的a)被METHOD宏中生成的evaluate-body函数绑定。因此,下面的代码示例中的关键点是METHOD宏,更具体地说是evaluate-body函数(这是应该进行绑定的地方,这意味着我的程序设计是合理的)。

是否有一种方法可以卫生地绑定这组任意的空闲标识符(目前只包含a,但它可能是任何东西,真的)?

代码语言:javascript
复制
#lang racket

(require (for-syntax syntax/parse))
(require racket/stxparam)

(struct actor (local-state methods))
(struct method (name formal-parameters body))

(define-syntax-parameter local-state-variables #f)

(define-syntax (ACTOR stx)
  (syntax-parse stx
    [(_ (LOCAL_STATE state-variable ...) method:expr ...+)
     #'(syntax-parameterize ([local-state-variables '(state-variable ...)])
         ; For the sake of simplicity, an actor is currently a list of message handlers
         (actor
          (make-list (length '(state-variable ...)) (void))
          (list method ...)))]))


(define-syntax (METHOD stx)
  (syntax-parse stx
    [(_ (name:id formal-parameter:id ...) body:expr ...+)
     (with-syntax ([(local-state-variable ...) (syntax-parameter-value #'local-state-variables)])
       #'(method
          'name
          '(formal-parameter ...)
          (λ (formal-parameter ... #:local-state [current-state '()])
            ; the "a" that will be bound here is different from the free identifier "a" in the body
            (define (evaluate-body local-state-variable ...)
              body ...
              (list local-state-variable ...))
            (apply evaluate-body current-state))))]))


(ACTOR (LOCAL_STATE a)
       (METHOD (save new-a)
               ; "a" is an unbound identifier
               (set! a new-a)))
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-12-14 21:06:33

为了使本地状态变量具有适当的词法上下文,需要将它们存储为标识符,而不是符号。也就是说,在ACTOR宏的结果中,需要将syntax-parameterize更改为:

代码语言:javascript
复制
#'(syntax-parameterize ([local-state-variables #'(state-variable ...)])
    #| rest of the template (unchanged)... |#)

注意将quote/'替换为syntax/#'。这将存储标识符及其词法上下文,而不是作为符号。

下一步是在METHOD宏中正确地引入它们。为此,只需将syntax-local-introduce应用于语法参数的值,该参数将向标识符添加宏导入范围。您还可以将with-syntax替换为syntax-parse#:with子句,以稍微简化一些事情,因此整个宏如下:

代码语言:javascript
复制
(define-syntax (METHOD stx)
  (syntax-parse stx
    [(_ (name:id formal-parameter:id ...) body:expr ...+)
     #:with (local-state-variable ...)
            (syntax-local-introduce (syntax-parameter-value #'local-state-variables))
     #'(method #| rest of the template (unchanged)... |#)]))

这会管用的。

这里需要syntax-local-introduce的原因可能有点令人困惑,但最直观的思考方法是,考虑到Racket目前使用的“范围集”卫生模型。为了使宏引入的绑定不与用户定义的绑定冲突,语法转换器返回的每个语法都有一个新的作用域,这个范围永远不会附加到用户编写的任何内容。当然,结果中的一些语法是用户提供的语法,因此宏扩展程序需要确保它不将新的作用域附加到这些语法对象。

一般来说,不可能确定哪些语法对象应该由用户提供,因为宏作者可以“弯曲”卫生,并从其他对象创建新的语法对象。幸运的是,解决方案简单而优雅:只需将宏导入作用域附加到用户提供的所有语法对象上,然后将它们传递给宏,然后在结果中的所有语法块上翻转作用域。这样,在翻转发生后,用户提供的语法对象将不具有宏导入范围。

syntax-local-introduce函数允许您手动翻转这个特殊作用域。在这种情况下,由于local-state-variables的值应该被视为宏的输入,但是宏扩展程序不会自动给出宏导入作用域(因为它不是宏的直接输入),所以您必须自己添加作用域。这样,宏扩展程序将在宏展开后删除作用域,标识符将以正确的词法上下文结束。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41139868

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档