2013-03-11 83 views
1

我需要一些函数,其中包括其他东西将定义一个新的全局符号。所以,我可以用这样的:从函数内部定义全局

(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 

这能实现的功能,或者是可以做到的,只有与帮助的宏?你能否建议任何可能的实现,或者至少提供一些可能有用的提示/参考?

+1

强烈建议朝向奥斯卡的回答。由于潜在的名称冲突和难以控制范围,动态定义全局变量通常是一个非常糟糕的主意。相反,将绑定绑定到散列表通常是更简单和更有效的方法。 – dyoo 2013-03-12 01:50:11

+0

如果您给我们更多的动机背景,那可能会提示更好的答案。你为什么要这样做?为了文档的功能?为了定义带有默认值的可选关键字参数的函数? – dyoo 2013-03-12 01:53:28

+1

其动机如下:有一种建模软件,它有自己的'语言',但语言很丑陋(恕我直言)。我正在尝试编写一个可以代替我的代码。我的文章中的格式化字符串显示了变量的定义如何在目标语言中看起来像。对于一些变量来说,创建这样一个字符串就足够了。对于其他人,我也需要在环绕内使用它们的值。我想奥斯卡的解决方案对我来说是最好的。 – skobls 2013-03-12 09:12:11

回答

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 
2

通常情况下,您无法按照所描述的方式完成您正在尝试完成的任务。你唯一的希望是将文件写入文件,然后将文件写入交互式会话。但即使如此。

在方案中,您不能引入顶级名称,例如您所需的s1,s2s3,但顶级名称除外。要做到这一点,你可以定义一个宏为:

>(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 

这得到完成它(我使用'忽略评论'),但正如我所说的,需要一个编译时间字符串列表。你可能会认为

一种可能性会工作,但不会,是使用eval为:

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

但“EVAL”仅适用于表情,不声明。这可能让我回到“加载”。

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")) 
+0

注意当然不是所有的Scheme都支持单参数'eval';在其他方案中,您可能必须将显式环境传递给'eval',例如'(交互 - 环境)'。 (并且,即使符合R5RS的Schemes也不需要支持'define'表达式,就像GoZoner的答案所暗示的那样)。所以确实,请检查您的实现文档。 – pnkfelix 2013-03-12 02:18:32

+0

EVAL不会移动地接受非表达式:“在指定的环境中计算表达式并返回其值,表达式必须是一个有效的Scheme表达式作为数据,并且环境说明符必须是由下面描述的三个过程之一返回的值。实现可以扩展eval以允许非表达式程序(定义)作为第一个参数“因此”(定义...)不能期望作为eval的第一个参数。 – GoZoner 2013-03-12 02:18:36

+0

当然,这个问题被贴上了Racket的标签,所以它不像我们需要考虑Ryan的答案。 :) – pnkfelix 2013-03-12 02:24:29