让我们把这个函数称为“动态定义”。
基本上,我想编写一个宏或lambda,其工作方式如下:
$ (dynamic-define "variable" 123)
$ variable
$ => 123我试过:
(define-syntax dynamic-define
(syntax-rules ()
((_ string <body>)
(eval `(define ,(string->symbol string) <body>)))))它如预期的那样工作,但似乎不是一个好的解决方案。
我试着用而不用像这样:
(define-syntax dynamic-define
(syntax-rules ()
((_ string <body>)
(define (string->symbol string) <body>))))但是当我尝试使用时,我得到了这个错误:
Error: invalid syntax (define (string->symbol "variable") 123)我该怎么办?
(请:请编辑这个问题,以适应本族语,请删除这一行)
发布于 2014-05-03 16:05:40
您遇到了一个根本的问题:您无法以“干净”的方式进行真正的动态定义,因此您尝试使用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的名称,就无法理解这段代码。没有这样的意义,编译就脱离了窗口--但更重要的是,正确性(或者通常,代码的意义)消失了。
根据我的经验,这种模式用哈希表和类似的设备处理要好得多。
发布于 2014-04-26 10:33:23
使用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
123https://stackoverflow.com/questions/23305997
复制相似问题