Binding 浅装订和深装订

Binding 浅装订和深装订,binding,functional-programming,language-agnostic,scheme,scoping,Binding,Functional Programming,Language Agnostic,Scheme,Scoping,我试图通过深度和浅层绑定来理解动态/静态范围的概念。下面是代码- (define x 0) (define y 0) (define (f z) (display ( + z y)) (define (g f) (let ((y 10)) (f x))) (define (h) (let ((x 100)) (g f))) (h) 我了解被调用函数使用调用函数的动态作用域值。所以使用动态绑定我应该得到答案-110。使用静态作用域,我将得到答案0。但我得到这些结果时并没有考虑浅绑定或深绑定。什么

我试图通过深度和浅层绑定来理解动态/静态范围的概念。下面是代码-

(define x 0)
(define y 0)
(define (f z) (display ( + z y))
(define (g f) (let ((y 10)) (f x)))
(define (h) (let ((x 100)) (g f)))
(h)

我了解被调用函数使用调用函数的动态作用域值。所以使用动态绑定我应该得到答案-
110
。使用静态作用域,我将得到答案
0
。但我得到这些结果时并没有考虑浅绑定或深绑定。什么是浅绑定和深绑定?它将如何改变结果?

这些课堂讲稿中有一个例子:这解释了概念,尽管我不喜欢它们的伪代码:

据我所知,在Scheme中这将是以下内容(我希望有一些更具描述性的名称:

(定义截止点0);a
(定义(高于截止值?人)
(>(年龄人)截止)
(定义(如果是person谓词则显示)
(让((截止20));b
(if)(谓语人称)
(展示人)
(定义(主要人物)
(让((截止35));c
(如果人员高于截止点,则显示?)
  • 在词法范围界定中,截止点中的截止点总是指绑定a
  • 使用公共Lisp实现的动态范围(我认为大多数实际语言都使用动态范围),在高于截止?截止的值,当用作显示if中的谓词时,将引用绑定b,因为在这种情况下,这是堆栈上最新的一次。这是浅绑定
  • 因此,剩下的选项是深度绑定,它的效果是将截止的值置于截止之上的范围内。请参阅绑定c
现在让我们来看看你的例子:

(定义x 0)
(定义y 0)
(定义(f z)(显示(+z y))
(定义(gf)(让((y10))(fx)))
(定义(h)(让((x100))(gf)))
(h)
我将添加一些新行,以便注释更容易,并使用注释标记每个变量的每个绑定,这些变量被多次绑定

(定义x 0);x0
(定义y0);y0
(定义(f z);f0
(显示(+zy)))
(定义(g f);f1
让((y 10));y1
(f x)))
(定义(h)
(让((x100));x1
(g(f)))
注意这里的f0和f1。它们很重要,因为在深度绑定中,作为参数传递的函数的当前环境绑定到该环境。这很重要,因为f作为参数传递到f中的g。因此,让我们讨论所有情况:

  • 对于词汇范围,结果是0。我认为这是最简单的情况
  • 对于动态范围和浅绑定,答案是110。(z的值是100,y的值是10。)这是您已经知道如何得到的答案
  • 最后,动态范围和深度绑定得到100。在h中,您将f作为参数传递,并捕获当前范围以提供函数(lambda(z)(显示(+z 0))),为了方便起见,我们将其称为ff。一旦进入g,对局部变量f的调用实际上是对ff的调用,当前值为x(从x1100开始),因此您正在打印(+100 0),即100
评论 正如我所说,我认为深度绑定有点不寻常,我不知道是否有很多语言真的实现了它。你可以把它看作是取函数,检查它是否有任何自由变量,然后用当前动态环境中的值填充它们。我认为这实际上在实践中没有得到太多的使用,而且这可能就是为什么您会收到关于这些术语的询问。不过,我确实看到它在某些情况下可能很有用。例如,在Common Lisp中,它同时具有词法和动态(称为“特殊”)变量,许多系统配置参数都是动态的。这意味着您可以在base 16中执行类似的操作来打印(因为打印基数是一个动态变量):

但是,如果您想返回一个函数来打印base 16中的内容,则不能执行以下操作:

(let ((*print-radix* 16))
  (lambda (value)
    (print value)))
因为有人可以使用该函数,所以我们将其称为print16,并执行以下操作:

(let ((*print-radix* 10))
  (print16 value))
值将以10为底打印。深度绑定将避免该问题。也就是说,您也可以使用浅绑定来避免它;您只需返回

(lambda (value)
  (let ((*print-radix* 16))
    (print value)))
相反

综上所述,我认为这个讨论在谈论“将函数作为参数传递”时会有点奇怪。这很奇怪,因为在大多数语言中,对表达式求值是为了产生一个值。变量是表达式的一种类型,对变量求值的结果就是该变量的表达式。我强调“the”这是因为它是这样的:一个变量在任何给定的时间都只有一个值。这种深度绑定和浅层绑定的表示使得它根据变量的求值位置为变量提供不同的值。这似乎很奇怪。我认为如果讨论的是您在求值时得到的结果,那么更有意义一个lambda表达式。然后你可以问“lambda表达式中自由变量的值是什么?”在浅绑定中,答案是“以后调用函数时,这些变量的动态值是什么。在深绑定中,答案是”计算lambda表达式时,无论这些变量的动态值是什么。”

那么我们就不必考虑“函数作为参数传递了”。

(let ((*print-radix* 10))
  (print16 value))
(lambda (value)
  (let ((*print-radix* 16))
    (print value)))