我目前正在尝试将变量分配给宏来存储内容:
(begin-for-syntax
(define a 0))
(define-syntax (foo stx)
(set! a (+ a 1))
(datum->syntax stx a))
(foo)
(foo)
(foo)
编译完这段代码后,repl显示" 1 2 3"。但是,当我进入"(foo)"在repl中,下一个数字是" 1"而不是" 4"这是我的预期。
1
2
3
> (foo)
1
它看起来像变量" a"编译完成后重置。当我需要"同样的事情发生了。这个代码在另一个模块中。
有可能解决这个问题吗?
答案 0 :(得分:2)
我无法解释为什么它不起作用,但我觉得在相位级别1中“隐藏”变量可能不是正确的方法。你可以通过模块和没有宏来实现相同的目标:
(module adder racket/base
(provide foo)
(define a 0)
(define (foo)
(set! a (add1 a))
a))
(require 'adder)
(foo)
(foo)
(foo)
打印
1
2
3
然后序列在REPL级别继续:
> (foo)
4
> (foo)
5
当然你也可以使用一个简单的闭包:
(define foo
(let ((a 1))
(lambda ()
(begin0
a
(set! a (add1 a))))))
答案 1 :(得分:1)
Racket具有separate compilation guarantee,这意味着单独模块的编译行为一致,因为突变和效果被重置,就像它们被单独编译一样,即使在一起编译时也是如此。这里REPL的行为方式相同。
解决这种特殊情况的一种方法是将宏扩展为执行突变的begin-for-syntax
,而不是尝试在宏变换器中执行此操作:
#lang racket
(begin-for-syntax
(define a 0))
(define-syntax (get-a stx)
(datum->syntax stx a))
(define-syntax (foo stx)
#'(begin
(begin-for-syntax
(set! a (+ a 1)))
(get-a)))
(foo)
(foo)
(foo)
在REPL中输入(foo)
会返回4
。
但是对于其他模块,这是不允许的,因为set!
不能改变来自单独模块的变量。