我对在 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 ?