Dun*_*yne 4 lisp macros scheme racket
我正在尝试编写一个包装器define,用于存储传递给它的值.我一直在接近它的步骤(一般来说是Lisp的新手,甚至是Scheme的新手)但是已经遇到了问题.
在Racket中,我开始:
> (require (lib "defmacro.ss"))
> (define-macro (mydefine thing definition)
`(define ,thing ,definition))
> (mydefine a 9)
> a
9
Run Code Online (Sandbox Code Playgroud)
好的,这很有效.在返回s-exprs之前,有时间在宏中执行某些操作:
> (define-macro (mydefine thing definition)
(display "This works")
`(define ,thing ,definition))
> (mydefine a "bob")
This works
> a
"bob"
Run Code Online (Sandbox Code Playgroud)
尼斯.但我不能为我的生活设置一个全局变量而不是显示一些东西:
> (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*
Run Code Online (Sandbox Code Playgroud)
任何关于如何实现这一点的建议将不胜感激.
我怀疑我正试图在这里游走当前,或者通过在Scheme中摆弄一个宏的全局变量,或者使用define-macro而不是学习用于宏创建的特定于Scheme的语法.
你正在反对Racket的相位分离 - 这意味着每个阶段(运行时和编译时)都在不同的世界中运行.正如Vijay所说,解决这个问题的一种方法是在运行时做你想做的事,但从长远来看,这可能不是你需要的.问题在于尝试这些事情通常意味着您需要在编译时级别存储一些语法信息.例如,假设您要存储所有已定义名称的名称,以便在第二个宏中使用,将其全部打印出来.你会这样做(我在这里使用理智的宏,define-macro是一个不应该用于实际工作的遗留黑客,你可以在指南中查看这些内容,然后在参考中):
#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))]))
Run Code Online (Sandbox Code Playgroud)
请注意,它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))))]))
Run Code Online (Sandbox Code Playgroud)