SICP 递归 let 定义
SICP recursive let definition
对于
(let ((fact
(lambda (n)
(if (= n 1)
1
(* n (fact (- n 1)))))))
(fact 10))
方案出错,我想确认我的推理是否正确,
因为(let ((var1 arg1)) body)
相当于在var1
绑定到arg1
的环境中评估body。
上面,当我们试图在绑定调用之前计算 arg1
时,我们找不到引用,因为这正是我们试图绑定的引用
但是为什么不抛出
(let ((fact (lambda (n)
(if (= n 1) 1 (* n (fact (- n 1)))))))
(display 10))
因为我们也试图在那里进行绑定。
还有为什么这个不抛出呢
(define factorial
(lambda (n)
(if (= n 0)
1
(* n (factorial (- n 1))))))
(factorial 10)
原因是只有当我们实际尝试查找“fact”的值时才会出现“variable fact is not bound”错误。考虑
(let ((fact (lambda (n) (if (= n 0)
1
(* n (fact (- n 1)))))))
(fact 0))
这不会导致错误,因为我们没有输入 else
子句,因此不会尝试使用未绑定变量 fact
的值。然而,用 1
尝试同样的事情确实给了我们错误。
我们在使用define
时不会运行出错,因为define
和let
有不同的规则。在 let
绑定中,您创建了一个新的词法范围,并且 let
绑定中 fact
的绑定不会从 let
中“泄漏”到外界.由于 let
赋值的右侧只能引用来自外部世界的绑定,因此右侧不能引用绑定 fact
.
但是,在 define
语句中,重点是在当前作用域中引入新绑定(而不是创建新作用域)。在 define
绑定中,赋值的右侧必须仅引用来自外部世界的变量——但这可能包括变量 define
d,只要访问它隐藏在 [= 后面28=] 因此懒惰地完成了。
事实上,考虑以下几点:
(define is-even
(lambda (n) (or (= n 0)
(is-odd (- n 1)))))
(define is-odd
(lambda (n) (and (not (= n 0))
(is-even (- n 1)))))
(display (is-odd 55))
在这种情况下,当我们实际调用 is-even
时,is-odd
是 define
d 在与 is-even
相同的范围内,因此我们可以查找它价值。类似地,当我们调用 is-odd
时,is-even
已经定义,因此我们对其值有一个绑定。
请注意以下不工作:
(define is-even
(lambda (n) (or (= n 0)
(is-odd (- n 1)))))
(display (let ((is-odd (lambda (n) (and (not (= n 0))
(is-even (- n 1))))))
(is-odd 55)))
这是因为这里的 is-odd
绑定 而不是 与 is-even
在同一范围内。它是在比 is-even
更本地化的绑定中定义的。 is-even
定义中引用的 is-odd
不能与 let
语句中创建的 is-odd
相同,因为此 is-odd
是本地绑定,因此不能在 is-even
定义的更广泛范围内引用。
如果我们使用“动态范围”的老式 LISP 概念,也称为“按名称调用语义”,后一个示例将工作得很好。但是,Scheme 不支持动态范围(在我看来这绝对是最好的)。
对于
(let ((fact
(lambda (n)
(if (= n 1)
1
(* n (fact (- n 1)))))))
(fact 10))
方案出错,我想确认我的推理是否正确,
因为(let ((var1 arg1)) body)
相当于在var1
绑定到arg1
的环境中评估body。
上面,当我们试图在绑定调用之前计算 arg1
时,我们找不到引用,因为这正是我们试图绑定的引用
但是为什么不抛出
(let ((fact (lambda (n)
(if (= n 1) 1 (* n (fact (- n 1)))))))
(display 10))
因为我们也试图在那里进行绑定。
还有为什么这个不抛出呢
(define factorial
(lambda (n)
(if (= n 0)
1
(* n (factorial (- n 1))))))
(factorial 10)
原因是只有当我们实际尝试查找“fact”的值时才会出现“variable fact is not bound”错误。考虑
(let ((fact (lambda (n) (if (= n 0)
1
(* n (fact (- n 1)))))))
(fact 0))
这不会导致错误,因为我们没有输入 else
子句,因此不会尝试使用未绑定变量 fact
的值。然而,用 1
尝试同样的事情确实给了我们错误。
我们在使用define
时不会运行出错,因为define
和let
有不同的规则。在 let
绑定中,您创建了一个新的词法范围,并且 let
绑定中 fact
的绑定不会从 let
中“泄漏”到外界.由于 let
赋值的右侧只能引用来自外部世界的绑定,因此右侧不能引用绑定 fact
.
但是,在 define
语句中,重点是在当前作用域中引入新绑定(而不是创建新作用域)。在 define
绑定中,赋值的右侧必须仅引用来自外部世界的变量——但这可能包括变量 define
d,只要访问它隐藏在 [= 后面28=] 因此懒惰地完成了。
事实上,考虑以下几点:
(define is-even
(lambda (n) (or (= n 0)
(is-odd (- n 1)))))
(define is-odd
(lambda (n) (and (not (= n 0))
(is-even (- n 1)))))
(display (is-odd 55))
在这种情况下,当我们实际调用 is-even
时,is-odd
是 define
d 在与 is-even
相同的范围内,因此我们可以查找它价值。类似地,当我们调用 is-odd
时,is-even
已经定义,因此我们对其值有一个绑定。
请注意以下不工作:
(define is-even
(lambda (n) (or (= n 0)
(is-odd (- n 1)))))
(display (let ((is-odd (lambda (n) (and (not (= n 0))
(is-even (- n 1))))))
(is-odd 55)))
这是因为这里的 is-odd
绑定 而不是 与 is-even
在同一范围内。它是在比 is-even
更本地化的绑定中定义的。 is-even
定义中引用的 is-odd
不能与 let
语句中创建的 is-odd
相同,因为此 is-odd
是本地绑定,因此不能在 is-even
定义的更广泛范围内引用。
如果我们使用“动态范围”的老式 LISP 概念,也称为“按名称调用语义”,后一个示例将工作得很好。但是,Scheme 不支持动态范围(在我看来这绝对是最好的)。