私はBrainharveyによるコンピュータープログラミングの構造と解釈を経験していました。私はそれを行う方法を理解することができなかったこの質問に出くわしました。
Schemeでラムダを使って再帰的なプロシージャを書くにはどうすればよいですか?
TL; DR:named let
(再帰関数をすぐに実行するrec
場合)または(後で実行するために再帰関数を保存する場合)を使用します。
通常の方法は、、またはnamedや。などの舞台裏letrec
を使用するものを使用することです。使用のバージョンは次のとおりです。letrec
let
rec
(factorial 10)
letrec
(letrec ((factorial (lambda (x)
(if (< x 1) 1
(* (factorial (- x 1)) x)))))
(factorial 10))
そして、namedを使用して同じことlet
:
(let factorial ((x 10))
(if (< x 1) 1
(* (factorial (- x 1)) x)))
ここでの重要な理解は、両方のバージョンがまったく同じであるということです。名前付きは、フォームlet
に展開される単なるマクロです。letrec
名前付きlet
バージョンは短いため、通常、再帰関数を作成するための推奨される方法です。
さて、再帰関数オブジェクトを実行するのではなく、直接返したい場合はどうでしょうか。そこでも、あなたは使うことができますletrec
:
(letrec ((factorial (lambda (x)
(if (< x 1) 1
(* (factorial (- x 1)) x)))))
factorial)
そこにも、これの省略形がありますが、namedを使用せずlet
、代わりにrec
:を使用します。
(rec (factorial x)
(if (< x 1) 1
(* (factorial (- x 1)) x)))
ここで使用することの良い点rec
は、関数オブジェクトを変数に割り当てて後で実行できることです。
(define my-fact (rec (factorial x)
(if (< x 1) 1
(* (factorial (- x 1)) x))))
(my-fact 10) ; => 3628800
再帰関数を作成するためのより理論的で「純粋な」方法は、Yコンビネータを使用することです。:-)しかし、ほとんどの実用的なスキームプログラムはこのアプローチを使用しないため、これ以上説明しません。
階乗本体を2回書く必要はありません;)
(((lambda (f)
(lambda (x)
(f f x)))
(lambda (fact x)
(if (= x 0) 1 (* x (fact fact (- x 1)))))) 5)
これは、ラムダを使用して5の階乗を計算する再帰関数です。
((lambda (f x)
(if (= x 0)
1
(* x (f f (- x 1)))))
(lambda (f x)
(if (= x 0)
1
(* x (f f (- x 1)))))
5)
Drracketでこのプログラムを実行すると、120が得られます:)