除(define variable value)
这样的常规定义时,还允许使用(define variable)
之类的未初始化定义,以后在set!
的帮助下将变量绑定到某个值时。
是否有程序允许测试符号是否是定义的(不一定是初始化的)变量?类似(defined? 'variable)
的内容如果#t
已定义,则会返回variable
,否则会#f
?
答案 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)
由实现者决定是否绑定到foo
和bar
的同一个未指定的值。
试试这个程序:
(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
)
)
)