gpt4 book ai didi

racket - 通过宏绑定(bind)自引用

转载 作者:行者123 更新时间:2023-12-03 14:19:04 25 4
gpt4 key购买 nike

我正在处理的项目定义了一些复杂的结构,这些结构接收消息并在它们自己的线程中运行。这些结构是用户定义的,并通过宏转换为线程和运行时的东西。粗略地说,我们可以说一个复杂的结构由一些实现逻辑的行为和一个产生行为实例的过程组成。在下面的代码中,我大大简化了这种情况,其中 create-thread-behaviour 定义的行为宏是一个简单的 thunk,可以通过 spawn 生成宏。我想实现一个行为的(一个实例)通过 self 向自己发送消息的能力。将绑定(bind)到 (current-thread) 的参数(〜运行行为的线程)。

我尝试使用 syntax-parameterize 来安装一些东西但由于某种原因无法让它工作。下面的代码实现了一个简单的应用程序,它应该阐明我想要实现的目标——特别感兴趣的是(未实现的)<self>引用底部。

#lang racket
(require (for-syntax syntax/parse))

(define-syntax (create-thread-behaviour stx)
(syntax-parse stx
[(_ body:expr ...+)
#'(λ () body ...)]))

(define-syntax (spawn stx)
(syntax-parse stx
[(_ behaviour:id)
#'(thread behaviour)]))


(define behaviour
(create-thread-behaviour
(let loop ()
(define message (thread-receive))
(printf "message: ~a~n" message)
(thread-send <self> "And this is crazy.")
(loop))))

(define instance (spawn behaviour))
(thread-send instance "Hey I just met you")

所以我尝试的带有语法参数的东西如下,它引发了自定义的“只能用于行为”错误。我知道我以前正确使用过语法参数,但也许我只是关注这个问题太久了。
(require racket/stxparam)

(define-syntax-parameter self
(lambda (stx) (raise-syntax-error (syntax-e stx) "can only be used in a behaviour")))

(define-syntax (spawn stx)
(syntax-parse stx
[(_ behaviour:id)
#'(thread
(lambda ()
(syntax-parameterize ([self #'(current-thread)])
(behaviour))))]))

最佳答案

你是对的,语法参数似乎是适合这里工作的工具。但是,在您使用它们时有两个问题会导致该问题。让我们一次拿一个。

首先,语法参数在语义上只是语法转换器,正如您最初使用 define-syntax-parameter 所见。 ,它将语法参数绑定(bind)到函数。您对 syntax-parameterize 的使用相比之下,将语法参数绑定(bind)到一段语法,这是错误的。相反,您还需要将其绑定(bind)到语法转换器。

实现您正在寻找的行为的一种简单方法是使用 make-variable-like-transformer函数来自 syntax/transformer ,这使得语法转换器,顾名思义,表现得像一个变量。不过,更一般地说,它实际上会生成一个行为类似于表达式的转换器,(current-thread)是。因此,您使用 syntax-parameterize实际上应该是这样的:

(require (for-syntax syntax/transformer))

(syntax-parameterize ([self (make-variable-like-transformer #'(current-thread))])
(behaviour))

这将避免在尝试使用 self 时出现“语法错误”错误。参数化后。

但是,您的代码中还有另一个问题,即当语法参数不能这样工作时,它似乎使用了像普通的非语法参数一样的语法参数。普通参数有效地动态作用域,所以使用 syntax-parameterize包装 (behavior)会调整 self在调用 behavior 的动态范围内.

然而,语法参数不是这样工作的。事实上,他们不能:Racket 在语法上是一种词法范围的语言,所以你真的不能有一个动态的语法绑定(bind):所有的语法转换器都是在编译时扩展的,所以在调用的动态范围内调整绑定(bind)是不可能的.语法参数完全是词法范围的,它们只是卫生地调整特定范围内的绑定(bind)。从这个意义上说,他们真的是 就像 let ,除了它们调整现有绑定(bind)而不是生成新绑定(bind) .

考虑到这一点,很明显将 syntax-parameterize填写 spawn真的不行,因为 behaviorspawn 之外进行词法定义.您可以移动使用 syntax-parameterizecreate-thread-behavior ,但是现在还有另一个问题,那就是这行不通:
(define (behavior-impl)
(define message (thread-receive))
(printf "message: ~a~n" message)
(thread-send self "And this is crazy.")
(behavior-impl))

(define behaviour
(create-thread-behavior
(behavior-impl)))

现在,再一次, selfsyntax-parameterize 的词汇范围之外使用,所以它不会被绑定(bind)。

您已经提到这是您实际操作的简化示例,因此您的实际示例可能需要更复杂的解决方案。如果是这样,您可能只需要要求 self仅在 create-thread-behavior 的词汇范围内绑定(bind).但是,您当前使用的 self非常简单,事实上,它永远不会改变:它总是 (current-thread) .因此,您实际上可以完全放弃语法参数并定义 self直接地:
(define-syntax self (make-variable-like-transformer #'(current-thread)))

现在 self将作为对参数值的可变外观引用在任何地方工作, current-thread .这可能是您真正想要的,因为它允许 self 的值真正动态作用域(因为它使用运行时参数,而不是语法参数),但它仍然使它看起来像一个变量而不是一个函数。

关于racket - 通过宏绑定(bind)自引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41431619/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com