相互に呼び出すことができる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
この場合、それを行うフォームは何が異なりますか?フォームは「letoverlambda」フォームではなく式にdefine
拡張されていますか(フォームを使用してLittle Schemerの本で同様のことが行われたことを思い出しますが、これがどのように機能するかはわかりません)。また、比較として、Common Lispはこの状況をどのように処理しますか?字句スコープのを使用することは可能ですか?lambda
((lambda (x) x x) (lambda (y) ...))
defun