从函数中定义全局

时间:2013-03-11 16:47:42

标签: scope macros scheme racket

我需要一些功能,其中包括一个新的全局符号。所以我可以像这样使用它:

(define (func-prototype symbol value comment)
  (define symbol value) ; this should somehow be reformulated
  (format "~a=~a   !~a\n" symbol value comment))

(define string-list (map func-prototype
                         '((s1 1 "first value")
                           (s2 20 "second value")
                           (s3 300 "third value))))

并且能够获得以下结果:

> string-list
'("s1=1  !first value\n"
  "s2=20  !second value\n"
  "s3=300  !third value\n")
> s1
1
> s2
20
> s3
300

这可以作为一个函数实现,还是只有在宏的帮助下才能实现?您能否建议任何可能的实施或至少提供一些可能有用的提示/参考?

3 个答案:

答案 0 :(得分:3)

我会重新考虑一般方法,使其更简单。我的建议:定义一个全局哈希表,并在函数内部添加绑定,例如:

(define value-map (make-hash))

(define (func-prototype symbol value comment)
  (hash-set! value-map symbol value)
  (format "~a=~a   !~a\n" symbol value comment))

像这样使用:

(define string-list
  (map (lambda (lst)
         (apply func-prototype lst))
       '((s1 1   "first  value")
         (s2 20  "second value")
         (s3 300 "third  value"))))

string-list
=> '("s1=1   !first  value\n"
     "s2=20   !second value\n"
     "s3=300   !third  value\n")

无论您何时需要引用哈希表中的一个符号,请执行以下操作:

(define (get key)
  (hash-ref value-map key))

(get 's1)
=> 1
(get 's2)
=> 20
(get 's3)
=> 300

答案 1 :(得分:2)

一般来说,不可能按照你描述的方式完成你想要完成的任务。您唯一的希望是将文件写入文件,然后将load该文件写入交互式会话。但即便如此。

在计划中,您无法引入顶级名称,例如您所需的s1s2s3,但顶级名称除外。为此,您可以将宏定义为:

>(define-syntax define-foo
  (syntax-rules ()
    ((_ name value)
     (define name value))))

>(define-foo s1 1)
<undefined>
> s1
1

如果你试图在一个函数中使用那个宏,它就没有骰子,因为函数的主体必须以一个表达式和任何定义形式结束,就像上面的宏会扩展到的那样,成为局部变量。那就是:

(define (func-prototype name value comment)
   (define-foo name value)
   name)

>(func-prototype 's1 1 "com")
1
> s1
<error>

如果你的字符串列表是一个常量,你可以采取的一种方法是:

> (define-syntax declare-variables
    (syntax-rules ()
      ((_ (name value comment) ...)
       (begin
         (define name value)
         ...))))

> (declare-variables (s1 1 "com") (s2 20 "com") (s3 300 "com"))
> s1
1

这样就完成了(我已经忽略了使用'comment')但是,正如我所说,需要一个编译时字符串列表。

您认为可行的一种可能性,但不会,将eval用作:

   (eval '(define s1 1) (environment ...))

但'eval'仅适用于表达式,不适用于声明。这使我回到“加载”的可能性。

答案 2 :(得分:2)

首先,考虑一下你是否真的想要这样做,或者一个不同的解决方案(如哈希表)是否也能正常工作。

您可以使用eval程序使用reflection and dynamic evaluation执行此操作。

;; define-variable-with-value! : symbol any -> void
(define (define-variable-with-value! name value)
  (eval `(define ,name (quote ,value))))

quote很重要;否则,您有可能将重新解释为表达式以进行评估。要查看差异,请考虑示例

(define-variable-with-value! 'x (list 'error "kaboom"))