如何在Scheme中取消定义变量?

时间:2010-08-15 11:19:35

标签: variables scheme undefined

如何在Scheme中取消定义变量?这可能吗?

8 个答案:

答案 0 :(得分:6)

你在这里感动神经。 Scheme没有关于顶级环境如何工作的非常明确的标准概念。为什么?因为Scheme标准代表了两组人之间的妥协,他们对Scheme应如何运作有着截然不同的想法:

  • 解释人群,如上所述,他们会看到顶级环境:运行时哈希表,在程序解释过程中逐步添加绑定。
  • 然后是汇编人群,他们将顶层环境视为必须在编译时完全可计算的东西(即,编译器必须能够最终确定将被绑定在顶层的所有名称环境)。

您的“我如何取消定义变量”问题仅在第一个模型中有意义。

请注意,解释模型(程序的顶级绑定取决于所采用的代码路径)使得有效编译Scheme代码变得更加困难,原因很多。例如,如果过程的名称是顶级绑定,并且可能不仅仅在运行时更改,甚至消失为虚无,那么Scheme编译器如何内联过程调用?

我坚定地参与编译阵营,所以我建议你避免编写依赖于在运行时添加或删除顶级绑定的代码,或者甚至需要使用top-等级变量(尽管这些变量通常是不可避免的)。一些Scheme系统(例如,Racket)能够产生相当好的编译代码,但如果你做出这些假设,你就会在这方面绊倒它们。

答案 1 :(得分:5)

在Scheme中,变量是使用lambda或其中一个let来定义的。如果你想让其中一个被“未定义”,那么你需要做的只是留下它们所在的范围。当然,这并不是真正取消它们,只是变量不再绑定到它之前的定义。

如果您正在使用(define)制作顶级定义,那么从技术上讲,您将定义一个函数。由于Scheme功能正常,功能永远不会消失。我认为从技术上讲,它存储在某种环境函数中,所以如果你非常熟悉你的实现(并且它不以某种方式得到保护),你可能会用你自己的globabl环境定义来覆盖它。除此之外,我会说你最好的选择是重新定义函数以返回空列表 - 这真的是空的。

答案 2 :(得分:3)

(set! no-longer-needed #f)

这是否达到了你想要的效果?您也可以在顶层使用define。

guile> (define nigel "lead guitar")
guile> nigel
"lead guitar"
guile> (define nigel #f)
guile> nigel
#f
guile> 

然后你可以重新define变量。这一切都取决于变量的范围,当然:见Greg's answer

答案 3 :(得分:3)

Scheme(R7RS)没有符合标准的方法来删除顶级绑定。

如果您评估一个非现有变量,则会收到错误:

(eval 'a)
; => ERROR: undefined variable: a

如果您定义它,变量将被添加到顶级环境中。

(define a 1)
(eval 'a)
; => 1

从现在开始,无论你做什么,如果访问变量,都不会出错。

如果将其设置为false,则会出现错误:

(set! a #f)
(eval 'a)
; => #f

即使您将其设置为未指定的内容,也不太可能出现错误:

(set! a (if #f #t))
(eval 'a)
; =>

方案可能采用非标准方式删除顶级绑定。 MIT Scheme提供函数unbind-variable

答案 4 :(得分:1)

您无法在标准Scheme中取消绑定变量。你可以设置!变量为'undefined,我猜,或者你可以编写一个metainterpreter来统一环境,允许你介绍你自己的定义变量的概念。

答案 5 :(得分:1)

我认为,如果你的观点是相当于“免费”或取消分配,那么你就不会有运气了。你无法取消分配变量。你 CAN 将它重新定义为小的东西,比如#f,但是一旦你完成了(定义foo'bar),变量foo将以某种形式存在,直到你结束程序。

另一方面,如果你使用let或者letrec,当然这个名字只存在于相关的关闭之前......

答案 6 :(得分:1)

如其他答案中所述,没有标准的方法来操作Scheme中的命名空间。对于特定实现,可能存在解决方案。

在Racket中,顶级变量存储在命名空间中。您可以使用namespace-undefined-variable删除变量。

无法删除局部变量。

http://docs.racket-lang.org/reference/Namespaces.html?q=namespace#%28def.%28%28quote.~23~25kernel%29._namespace-undefine-variable%21%29%29

答案 7 :(得分:0)

我认为你的问题不是愚蠢的。在AutoLISP中有未存在的(未定义的)变量apriori supposted值“nil”(即使变量在内存中不存在 - 这意味着 - 如果它不在变量表中 - 那么值为“nil” - “false”) 。这也意味着错误。它也是空列表。如果您编写某种列表处理功能,只需通过以下方式进行初始测试即可:

(if input-list ....)

如果要明确取消定义任何变量,可以执行以下操作:

(setq old-var nil); or: (setq old-var ())

我喜欢它。关键字“setq”表示“定义”。其他方言中的边界和非绑定变量有什么更好的?您必须测试它们是否存在,如果它们是列表,您需要垃圾收集器,您可能不会取消定义变量以显式释放内存。如果未定义变量“my-list”,则无法写入以下命令:

(define my-list (cons 2 my-list))

所以我认为AutoLISP的编程方式要好得多。可能,我写的,你可以在那里使用。不幸的是,AutoLISP仅适用于某些CAD工程图形系统。