如何制作"定义"在SISC Scheme的第一个参数中接受字符串?

时间:2014-04-26 02:40:23

标签: scheme sisc

让我们将此函数称为“动态定义”。

基本上我想写一个像这样工作的宏或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)

我该怎么办?

(请:编辑此问题以适合英语原文并删除此行)

2 个答案:

答案 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