方案中的词法范围
lexical scoping in scheme
我正在尝试理解词法和动态范围的概念以及它们之间的区别。
我们来看看下面的代码:
(let ((a 1)
(b 2))
(letrec ((f (lambda () F))
(g (lambda (c) G)))
(lambda (d)
(+ (f) (g b)))))
对于表达式 F 和 G,哪些变量在 (lambda(d)...)
的词法范围内?
(lambda(d)...)
将 d
作为绑定变量,将 f
、g
a
b
和所有全局范围作为自由变量.
编辑
只是为了演示 Scheme 和一些其他语言中的代码,其中相同的绑定是动态的。由于您的两个函数都不会相互调用,因此您不妨将它们保持在相同的位置 let
:
(define test
(let ((a 1)
(b 2)
(f (lambda () F))
(g (lambda (c) G)))
(lambda (d)
(+ (f) (g b)))))
;; for the test we need the F and G defined
(define F 10)
(define G 20)
(test 4) ; ==> 30 (aka (+ F G))
发生的事情是,当 lambda
被求值时,即使 let
消失了,它从词法范围使用的变量仍然存在。在动态范围内,这是不正确的:
(test 4)
; ERROR f: unbound identifier
原因是 a
、b
、f
和 g
在评估兰巴时存在 none 变量被捕获就像在词法范围内一样,因此当过程 test
被创建时,局部变量的 none 就不再存在了。其实你还不如这样写:
;; in a dynamic lisp this s the same
(define test
(lambda (d)
(+ (f) (g b))))
并且在调用函数(又名动态)时必须确保变量存在
(define g (lambda (v) 1337))
(define f (lambda () 3.1415927))
(define b 13)
(test 4) ; ==> 1340.1415927
现在,如果您要在全局范围内添加上述定义并保留原始定义,您仍然会得到 30
,因为词法 lisp 使用更紧密的词法绑定而不是全局绑定。
另一个很好的例子是:
(define x 10)
(define (test v)
(+ x v))
(let ((x 20))
(test 10))
; ==> ?
在词法 lisp 中,结果总是 20
,因为 test
不知道 let
,因为它不在其词法范围内。它的 x
始终是全局绑定 x
。在动态 lisp 中,let
中的 x
从运行时的角度来看是最接近的,这将导致 30
,因为 test
中的 x
是与 let
中的 x
相同,它隐藏全局 x
.
我正在尝试理解词法和动态范围的概念以及它们之间的区别。 我们来看看下面的代码:
(let ((a 1)
(b 2))
(letrec ((f (lambda () F))
(g (lambda (c) G)))
(lambda (d)
(+ (f) (g b)))))
对于表达式 F 和 G,哪些变量在 (lambda(d)...)
的词法范围内?
(lambda(d)...)
将 d
作为绑定变量,将 f
、g
a
b
和所有全局范围作为自由变量.
编辑
只是为了演示 Scheme 和一些其他语言中的代码,其中相同的绑定是动态的。由于您的两个函数都不会相互调用,因此您不妨将它们保持在相同的位置 let
:
(define test
(let ((a 1)
(b 2)
(f (lambda () F))
(g (lambda (c) G)))
(lambda (d)
(+ (f) (g b)))))
;; for the test we need the F and G defined
(define F 10)
(define G 20)
(test 4) ; ==> 30 (aka (+ F G))
发生的事情是,当 lambda
被求值时,即使 let
消失了,它从词法范围使用的变量仍然存在。在动态范围内,这是不正确的:
(test 4)
; ERROR f: unbound identifier
原因是 a
、b
、f
和 g
在评估兰巴时存在 none 变量被捕获就像在词法范围内一样,因此当过程 test
被创建时,局部变量的 none 就不再存在了。其实你还不如这样写:
;; in a dynamic lisp this s the same
(define test
(lambda (d)
(+ (f) (g b))))
并且在调用函数(又名动态)时必须确保变量存在
(define g (lambda (v) 1337))
(define f (lambda () 3.1415927))
(define b 13)
(test 4) ; ==> 1340.1415927
现在,如果您要在全局范围内添加上述定义并保留原始定义,您仍然会得到 30
,因为词法 lisp 使用更紧密的词法绑定而不是全局绑定。
另一个很好的例子是:
(define x 10)
(define (test v)
(+ x v))
(let ((x 20))
(test 10))
; ==> ?
在词法 lisp 中,结果总是 20
,因为 test
不知道 let
,因为它不在其词法范围内。它的 x
始终是全局绑定 x
。在动态 lisp 中,let
中的 x
从运行时的角度来看是最接近的,这将导致 30
,因为 test
中的 x
是与 let
中的 x
相同,它隐藏全局 x
.