我试图通过深度和浅层绑定来理解动态/静态范围的概念。以下是代码 -
(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
。但是我得到了这些结果而没有考虑浅层或深层绑定。什么是浅层和深层绑定,它将如何改变结果?
答案 0 :(得分:2)
这些讲义6. Names, Scopes, and Bindings中有一个例子:它解释了这些概念,虽然我不喜欢他们的伪代码:
thres:integer function older(p:person):boolean return p.age>thres procedure show(p:person, c:function) thres:integer thres:=20 if c(p) write(p) procedure main(p) thres:=35 show(p, older)
最好的我可以告诉,这将是Scheme中的以下内容(我希望有一些更具描述性的名称:
(define cutoff 0) ; a
(define (above-cutoff? person)
(> (age person) cutoff))
(define (display-if person predicate)
(let ((cutoff 20)) ; b
(if (predicate person)
(display person))))
(define (main person)
(let ((cutoff 35)) ; c
(display-if person above-cutoff?)))
现在让我们来看看你的例子:
(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)
我将添加一些换行符,以便更容易进行评论,并使用注释标记每个绑定多次绑定的变量的每个绑定。
(define x 0) ; x0
(define y 0) ; y0
(define (f z) ; f0
(display (+ z y)))
(define (g f) ; f1
(let ((y 10)) ; y1
(f x)))
(define (h)
(let ((x 100)) ; x1
(g f)))
注意那里的f0和f1。这些很重要,因为在深度绑定中,作为参数传递的函数的当前环境绑定到该环境。这很重要,因为 f 作为参数传递给 f 中的 g 。所以,让我们涵盖所有案例:
正如我所说的,我认为深层绑定有点不寻常,我不知道是否有多种语言实际实现了这一点。您可以将其视为获取函数,检查它是否具有任何自由变量,然后使用当前动态环境中的值填充它们。我不认为这实际上在实践中被大量使用,这可能是你收到some comments询问这些条款的原因。我确实看到它在某些情况下可能有用。例如,在Common Lisp中,它既有词法又有动态(称为'#39;特殊')变量,许多系统配置参数都是动态的。这意味着您可以执行此类操作以在基础16中打印(因为 * print-radix * 是动态变量):
(let ((*print-radix* 16))
(print value))
但是如果你想要返回一个能在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)))
代替。
所有这一切,我认为当讨论"传递函数作为参数时,这种讨论会变得有些奇怪。这很奇怪,因为在大多数语言中,表达式被评估为产生值。 变量是一种表达式, 评估变量的结果是该变量的表达式。我强调""那里,因为它是这样的:变量在任何给定时间都有一个值。这种深度和浅层绑定的表示使得它根据评估的位置为变量赋予不同的值。这看起来很奇怪。我认为更有意义的是,如果讨论的内容是关于评估 lambda表达式时得到的内容。然后你可以问" lambda表达式中自由变量的值是"?在浅层绑定中,答案将是"无论这些变量的动态值是何时稍后调用该函数。在深度绑定中,答案是"无论这些变量的动态值是什么时候评估lambda表达式。"
然后我们不必考虑"函数作为参数传递。"整个"函数作为参数传递#34;是奇怪的,因为当你将一个函数作为参数传递(捕获它的动态环境)时会发生什么,以及你将它传递给它然后将它传递到其他地方的什么?动态环境应该重新绑定吗?