组!来自Scheme宏的全局?

时间:2011-04-01 06:22:20

标签: macros lisp scheme racket

我正在尝试为define编写一个包装器,它存储传递给它的值。我一直在接近它的步骤(一般来说是Lisp的新手,甚至是Scheme的新手)但是已经遇到了问题。

在Racket中,我从:

开始
> (require (lib "defmacro.ss"))
> (define-macro (mydefine thing definition)
      `(define ,thing ,definition))
> (mydefine a 9)
> a
9

好的,这很有效。在返回s-exprs之前,有时间在宏中执行某些操作:

> (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的语法来创建宏。

2 个答案:

答案 0 :(得分:6)

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

#lang racket
(define-for-syntax defined-names '())
(define-syntax (mydefine stx)
  (syntax-case stx ()
    [(_ name value)
     (identifier? #'name)
     (begin (set! defined-names (cons #'name defined-names))
            #'(define name value))]
    ;; provide the same syntactic sugar that `define' does
    [(_ (name . args) . body)
     #'(mydefine name (lambda args . body))]))

请注意,defined-names是在语法级别定义的,这意味着普通的运行时代码无法引用它。实际上,您可以将它绑定到运行时级别的不同值,因为这两个绑定是不同的。既然已经完成了,你可以编写使用它的宏 - 即使defined-names在运行时不可访问,它在语法级别是一个普通的绑定,所以:

(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))))]))

答案 1 :(得分:4)

语句(set! *myglobal* "This does not")转换器环境中执行,而不是在正常环境中执行。所以它无法找到*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

如果Scheme实施没有提供define-macrodefine-syntaxmydefine可以定义为:

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