让我们将此函数称为“动态定义”。
基本上我想写一个像这样工作的宏或lambda:
$ (dynamic-define "variable" 123)
$ variable
$ => 123
我试过了:
(define-syntax dynamic-define
(syntax-rules ()
((_ string <body>)
(eval `(define ,(string->symbol string) <body>)))))
它按预期工作,但似乎不是一个好的解决方案。
我尝试不使用eval这样使用:
(define-syntax dynamic-define
(syntax-rules ()
((_ string <body>)
(define (string->symbol string) <body>))))
但是当我尝试使用时,我收到了这个错误:
Error: invalid syntax (define (string->symbol "variable") 123)
我该怎么办?
(请:编辑此问题以适合英语原文并删除此行)
答案 0 :(得分:2)
您遇到了一个基本问题:您无法以“干净”的方式进行真正的动态定义,因此您尝试使用eval
。请注意,上面的两个解决方案都不是动态的 - 他们给你的只是能够写"foo"
而不是foo
。正如我在其他地方所说的那样,使用eval
通常是不好的,在这种情况下它会更糟,因为它是从宏使用的eval
,这使得它非常奇怪。除了在宏中使用隐式准引用之外,还会使事情变得更加混乱。您也可以将整个事物定义为普通函数:
(define (dynamic-define string <body>)
(eval `(define ,(string->symbol string) ,<body>)))
如果你真的需要这个,那么最好退后一步,仔细考虑你需要什么。一方面,上述解决方案不是动态的,因为它们需要使用带有字符串语法的宏
(dynamic-define "foo" 123) ; instead of (define foo 123)
但是如何获得一个带有字符串的真实动态定义呢?您可能希望这可以定义b
:
(define a "b")
(dynamic-define a 123)
但是当你考虑它与其他绑定的交互方式时,这只会变得更加混乱。例如:
(define y 123)
(define (foo s)
(define x 456)
(dynamic-define s 789)
(+ x y))
现在,假设dynamic-define
执行了您希望它执行的操作,请考虑使用(foo "x")
和(foo "y")
获得的内容。更糟糕的是,请考虑(foo "s")
和(foo "+")
。更糟糕的是,
(foo (random-element '("x" "y" "s" "+" "define")))
?显然,如果这个dynamic-define
确实做了一些动态定义,那么没有意识到你可以在不事先知道将调用foo
名称的情况下制作这段代码。如果没有这样的意义,编译就会消失 - 但更重要的是,正确性(或者通常,代码的意思)会消失。
根据我的经验,使用哈希表和类似设备可以更好地处理这种模式。
答案 1 :(得分:1)
使用define-macro
#> (define-macro (dynamic-define varstr val)
`(define ,(string->symbol varstr) ,val))
#> (dynamic-define "variable" 123)
#> variable
123
使用syntax-case
#> (define-syntax dynamic-define
(lambda (stx)
(syntax-case stx ()
((k varstr val)
(with-syntax ([var (datum->syntax-object
#'k
(string->symbol (syntax-object->datum #'varstr)))])
#'(define var val))))))
#> (dynamic-define "variable" 123)
#> variable
123