Macros 设置全局方案宏?

Macros 设置全局方案宏?,macros,lisp,scheme,racket,Macros,Lisp,Scheme,Racket,我正在尝试为define编写一个包装器,用于存储传递给它的值。我一直在以很小的步伐接近它(对于Lisp一般来说是新的,对于Scheme来说甚至是更新的),但是遇到了一堵墙 在《球拍》中,我从以下几点开始: > (require (lib "defmacro.ss")) > (define-macro (mydefine thing definition) `(define ,thing ,definition)) > (mydefine a 9) > a 9

我正在尝试为
define
编写一个包装器,用于存储传递给它的值。我一直在以很小的步伐接近它(对于Lisp一般来说是新的,对于Scheme来说甚至是更新的),但是遇到了一堵墙

在《球拍》中,我从以下几点开始:

> (require (lib "defmacro.ss"))
> (define-macro (mydefine thing definition)
      `(define ,thing ,definition))
> (mydefine a 9)
> a
9
好的,这样行。在返回s-EXPR之前,在宏中执行某些操作的时间:

> (define-macro (mydefine thing definition)
    (display "This works")
    `(define ,thing ,definition))
> (mydefine a "bob")
This works
> a
"bob"
很好。但我无法让它设置一个全局变量,而不是显示某些内容:

> (define *myglobal* null)
> (define-macro (mydefine thing definition)
    (set! *myglobal* "This does not")
    `(define ,thing ,definition))
> (mydefine a ":-(")
set!: cannot set identifier before its definition: *myglobal*
任何关于如何实现这一目标的建议都将不胜感激

我怀疑我试图逆流而上,要么在Scheme中通过摆弄宏中的全局变量,要么使用define macro而不是学习特定于Scheme的宏创建语法。

语句
(set!*myglobal*“This nots”)
在transformer环境中执行,不是正常的环境。因此它无法找到
*myglobal
。我们需要在定义了
*myglobal*
的环境中执行这两个表达式

这里有一个解决方案:

(define *defined-values* null)

(define-macro (mydefine thing definition)  
  `(begin
     (set! *defined-values* (cons ,definition *defined-values*))
     (define ,thing ,`(car *defined-values*))))


> (mydefine a 10)
> (mydefine b (+ 20 30))
> a
10
> b
50
> *defined-values*
(50 10)
> (define i 10)
> (mydefine a (begin (set! i (add1 i)) i)) ;; makes sure that `definition` 
                                           ;; is not evaluated twice.
> a
11
如果方案实现没有提供
define宏
,但有
define语法
mydefine
可以定义为:

(define-syntax mydefine
  (syntax-rules ()
    ((_ thing definition)
     (begin       
       (set! *defined-values* (cons definition *defined-values*))
       (define thing (car *defined-values*))))))

您正在运行Racket的阶段分离——这意味着每个阶段(运行时和编译时)在不同的世界中运行。正如Vijay所指出的,解决这一问题的一种方法是在运行时执行您想要的操作,但从长远来看,这可能不是您所需要的。问题是,尝试这些东西通常意味着您需要在编译时级别存储一些语法信息。例如,假设要存储所有已定义名称的名称,以便在第二个宏中使用,该宏将全部打印出来。您可以按如下方式执行此操作(我在这里使用sane宏,
define macro
是一种不应用于实际工作的遗留攻击,您可以在中查找这些内容,然后在中查找):

请注意,
定义的名称
是在语法级别定义的,这意味着正常运行时代码不能引用它。事实上,您可以在运行时级别将其绑定到不同的值,因为这两个绑定是不同的。至此,您就可以编写使用它的宏了--即使在运行时无法访问
定义的名称
,但它在语法级别上是一个普通绑定,因此:

(define-syntax (show-definitions stx)
  (syntax-case stx ()
    [(_) (with-syntax ([(name ...) (reverse defined-names)])
           #'(begin (printf "The global values are:\n")
                    (for ([sym (in-list '(name ...))]
                          [val (in-list (list name ...))])
                      (printf "  ~s = ~s\n" sym val))))]))
(define-syntax (show-definitions stx)
  (syntax-case stx ()
    [(_) (with-syntax ([(name ...) (reverse defined-names)])
           #'(begin (printf "The global values are:\n")
                    (for ([sym (in-list '(name ...))]
                          [val (in-list (list name ...))])
                      (printf "  ~s = ~s\n" sym val))))]))