1

私はBrainharveyによるコンピュータープログラミングの構造と解釈を経験していました。私はそれを行う方法を理解することができなかったこの質問に出くわしました。

Schemeでラムダを使って再帰的なプロシージャを書くにはどうすればよいですか?

4

3 に答える 3

8

TL; DR:named let(再帰関数をすぐに実行するrec場合)または(後で実行するために再帰関数を保存する場合)を使用します。


通常の方法は、、またはnamedや。などの舞台裏letrecを使用するものを使用することです。使用のバージョンは次のとおりです。letrecletrec(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コンビネータを使用することです。:-)しかし、ほとんどの実用的なスキームプログラムはこのアプローチを使用しないため、これ以上説明しません。

于 2012-06-27T17:08:47.450 に答える
5

階乗本体を2回書く必要はありません;)

(((lambda (f)
   (lambda (x)
     (f f x)))
 (lambda (fact x)
   (if (= x 0) 1 (* x (fact fact (- x 1)))))) 5)
于 2012-06-28T10:30:07.433 に答える
3

これは、ラムダを使用して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が得られます:)

于 2012-06-27T17:48:34.897 に答える