测试Scheme中变量的定义

时间:2015-07-22 11:41:51

标签: scheme

(define variable value)这样的常规定义时,还允许使用(define variable)之类的未初始化定义,以后在set!的帮助下将变量绑定到某个值时。

是否有程序允许测试符号是否是定义的(不一定是初始化的)变量?类似(defined? 'variable)的内容如果#t已定义,则会返回variable,否则会#f

3 个答案:

答案 0 :(得分:2)

表单(define var)是非标准扩展名。

根据R5RS define具有以下形式之一:

(define <variable> <expression>)
(define (<variable> <formals>) <body>)
(define (<variable> . <formal>) <body>)

据我所知,R6RS和R7RS也是如此。

在您的实施中,(define foo)很可能会扩展为(define foo the-undefined-value)。这意味着你可以使用(if (eq? foo the-undefined-value) ...) to test whether foo已经初始化了。

http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-8.html#%_idx_190

更新

我查了R6RS并说:

(define <variable> <unspecified>)
where <unspecified> is a side-effect-free expression returning 
an unspecified value.

考虑

(define foo)
(define bar)

由实现者决定是否绑定到foobar的同一个未指定的值。

试试这个程序:

(define unspecified)
(define unspecified1)
(eq? unspecified unspecified1)

如果程序评估为#t,那么您可以编写initialized?这样的谓词:

(define unspecified)
(define (initialized? x) (not (eq? x unspecified)))

(define test)
(initialized? test)
(set! test 42)
(initialized? test)

答案 1 :(得分:1)

根据scheme report (standard) define用于定义变量。 (将其存在)使用define而不使用(define test)之类的表达式将变量定义为实现选择的某个值。

它只能在相同的范围内对同一个变量使用一次,因此set!是将现有变量更改为其他变量,但它不能删除它的存在。

报告中没有任何内容可以删除绑定或检查绑定是否存在。使用没有定义的变量将具有未定义的后果。

实施可能具有报告之外的功能。这些东西通常是方案系统的内容应该知道的东西,它们可能会暴露给用户,但它依赖于实现而不是标准。

答案 2 :(得分:0)

有一个简单的基于try-catch的通用解决方案。我已经在Gambit v4.9.3。上对其进行了测试。

(define (defined? var-symbol)
 (with-exception-handler
  (lambda (e) void)
  (lambda () (not (eq? void (eval var-symbol))))
 )
)

这是测试用例:

> (defined? 'a)
#f
> (define a 123)
> (defined? 'a) 
#t
> (defined? 'x)
#f
> (define x)
> (defined? 'x)
#t
> (defined? 'f)
#f
> (define (f a b) (+ a b))
> (defined? 'f)           
#t

使用此方法,您可以进行条件定义:

(define (define-if-not var-symbol init)
 (if (defined? var-symbol) void
  (let ((value (init)))
   (eval (list 'define var-symbol value))
   value
  )
 )
)

测试:

> (define a 'abc)
> (define (make-123) 123)
> (define-if-not 'a make-123)
#<procedure #2 void>
> (define-if-not 'b make-123)
123
> a
abc
> b
123

define-if-not的变体有一个警告:如果该值是一个符号,则eval会将其视为引用。这是简短的演示:

> (define value 123)
> (eval (list 'define 'a value))
> (define value 'abc)           
> (eval (list 'define 'a value))
*** ERROR -- Unbound variable: abc

以下[讨厌]解决方案为Gambit克服了:

(define define-if-not-private)

(define (define-if-not var-symbol init)
 (if (defined? var-symbol) void
  (let ((value (init)))
   (set! define-if-not-private (lambda () value))
   (eval (list 'define var-symbol '(define-if-not-private)))
   value
  )
 )
)