浅层和深层绑定

时间:2015-12-02 19:18:31

标签: 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。但是我得到了这些结果而没有考虑浅层或深层绑定。什么是浅层和深层绑定,它将如何改变结果?

1 个答案:

答案 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?)))
  • 使用词汇范围截止 截止总是指绑定 a
  • 使用动态范围,因为它在Common Lisp中实现(以及大多数具有动态范围的实际语言,我认为), cutoff 的值 cut-cutoff?,当用作 display-if 中的谓词时,将引用绑定 b ,因为在这种情况下,它是堆栈中最新的。这是浅层绑定
  • 所以剩下的选项是深度绑定,它具有 cutoff 的值 over-cutoff?指的是绑定 c

现在让我们来看看你的例子:

  
(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 。所以,让我们涵盖所有案例:

  • 使用词汇范围,结果为0.我认为这是最简单的情况。
  • 使用动态范围和浅层绑定,答案为110.(z的值为100,y的值为10.)这就是您已经知道如何获得的答案。
  • 最后,动态范围和深度绑定,你得到100.在 h 中,你传递 f 作为参数,并捕获当前范围以给我们一个函数(lambda(z)(display(+ z 0))),为方便起见,我们将其称为 ff 。一旦你在 g 中,对本地变量 f 的调用实际上是对 ff 的调用,该调用是通过当前值 x (来自 x1 ,100),因此您要打印(+ 100 0),即100。 / LI>

评论

正如我所说的,我认为深层绑定有点不寻常,我不知道是否有多种语言实际实现了这一点。您可以将其视为获取函数,检查它是否具有任何自由变量,然后使用当前动态环境中的值填充它们。我不认为这实际上在实践中被大量使用,这可能是你收到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;是奇怪的,因为当你将一个函数作为参数传递(捕获它的动态环境)时会发生什么,以及你将它传递给它然后将它传递到其他地方的什么?动态环境应该重新绑定吗?

相关问题与解答