首页 > 解决方案 > Scheme语言中是否有正常的“设置”功能(不是特殊形式)?

问题描述

Scheme语言中是否有正常的“设置”功能(不是特殊形式)或某种方式来实现它?

我想编写类似的代码:

(map (lambda (var)
       (set var 0))
     '(a b c))

它可以为列表中的变量分配一个值(这里是'0')(这里它们是'a','b'和'c')。

标签: scheme

解决方案


不。看看为什么不考虑这样的事情:

(define (mutant var val)
  (let ((x 1))
    (set var val)
    x))

现在,应该(mutant 'x 3)返回什么?如果它应该返回3,那么:

  • set不能是一个函数,因为它需要访问 ; 的词法环境mutant
  • 不可能对这个函数进行任何合理的编译。

如果你想set成为一个函数,那么灾难就会随之而来。考虑这个定义:

(define (mutant-horror f)
  (let ([x 3])
    (f)
    x))

现在,您会认为可以对此进行优化:

(define (mutant-horror f)
  (f)
  3)

但它不能。因为你可能会这样称呼它:

(mutant-horror (λ () (set 'x 3)))

或者,更一般地说,您可以使用一个函数调用它,该函数最终在某个函数中间接调用它可能最终会说(set 'x 3).

这意味着根本无法优化绑定,这是一场灾难。它至少也非常接近词法范围不可能的含义:如果还有set一个名为getexists 的函数,它检索符号的绑定,那么您基本上就拥有了动态范围。这反过来又使诸如尾呼叫消除之类的事情至少变得困难并且可能是不可能的(实际上set可能是自己做到的)。

像这样的原因是为什么即使是非常古老的 Lisp,其中set确实存在并且表面上确实有效,实际上对已编译的代码做出了特殊的豁免,其中set 不起作用(例如,参见 Lisp 1.5 程序员手册(PDF 链接),附录 D。编译代码和解释代码语义之间的这种差异是后来 Lisps 和 Lisp 相关语言(如 CL 和 Scheme)消除的事情之一。


相反,如果您想要类似 Common Lisp 语义的东西,那么等价的东西

(defun mutant (var val)
  (let ((x 1))
    (set var val)
    x))

将返回1(除非x是全局(见下文)特殊变量,在这种情况下它可能会返回其他内容)并作为副作用修改由var(可能是x)命名的任何符号的值单元格,然后,好吧,Scheme完全没有这个概念,总的来说这是一件好事。

请注意,该函数的修改版本也适用于局部特殊变量:

(defun mutant/local-special (a b)
  (let ((x 1))
    (declare (special x))
    (set a b)
    x))

但在这种情况下,您始终知道发生了特殊绑定,因为您始终可以看到声明。


推荐阅读