我对在 Scheme 中定义多个可以相互调用的词法范围函数感到好奇。在 SICP 工作时,我使用块结构生成了以下函数来解决练习 1.8(使用牛顿法计算立方根):
(define (cbrt x)
(define (good-enough? guess prev-guess)
(< (/ (abs (- guess prev-guess))
guess)
0.001))
(define (improve guess)
(/ (+ (/ x (square guess))
(* 2 guess))
3))
(define (cbrt-iter guess prev-guess)
(if (good-enough? guess prev-guess)
guess
(cbrt-iter (improve guess)
guess)))
(cbrt-iter 1.0 0.0))
这很好用,但它让我想知道 Scheme(也许还有 Common Lisp)如何使用词法作用域和let
表单来处理相同的场景。我尝试使用let
以下 kludgy 代码来实现它:
(define (cbrt x)
(let ((calc-cbrt
(lambda (guess prev-guess)
(let ((good-enough?
(lambda (guess prev-guess)
(< (/ (abs (- guess prev-guess))
guess)
0.001))))
(good-enough? guess prev-guess))
(let ((improve
(lambda (guess)
(/ (+ (/ x (square guess))
(* 2 guess))
3))))
(improve guess))
(let ((cbrt-iter
(lambda (guess prev-guess)
(if (good-enough? guess prev-guess)
guess
(cbrt-iter (improve guess)
guess)))))
(cbrt-iter 1.0 0.0)))))
(calc-cbrt 1.0 0.0)))
我在下面看到的问题是cbrt-iter
尝试调用该good-enough?
过程时。由于该good-enough?
过程仅在第一个嵌套 let
块的范围内是本地的,cbrt-iter
因此无法访问它。似乎可以通过将cbrt-iter
函数嵌套在 的let
中来解决good-enough
,但这似乎也很笨拙和尴尬。
define
在这种情况下,有什么不同的形式?表单是否define
扩展到lambda
表达式而不是“让 lambda”表单(我记得在 Little Schemer 书中使用表单做了类似的事情((lambda (x) x x) (lambda (y) ...))
,但我不确定这将如何工作)。此外,作为比较,Common Lisp 如何处理这种情况——是否可以使用词法范围defun
的 's ?