スキームでテール反発力関数をどのように実装するのか疑問に思いましたか?
スキーム用に定義された再帰的なものがあります:
(define power-is-fun
(lambda (x y)
(cond [(= y 0)
1]
[(> y 0)
(* (power-is-fun x (- y 1)) x)])))
しかし、私はもう一方がどうあるべきかを完全に理解することはできません。
スキームでテール反発力関数をどのように実装するのか疑問に思いましたか?
スキーム用に定義された再帰的なものがあります:
(define power-is-fun
(lambda (x y)
(cond [(= y 0)
1]
[(> y 0)
(* (power-is-fun x (- y 1)) x)])))
しかし、私はもう一方がどうあるべきかを完全に理解することはできません。
答えは似ています、あなたはただパラメータとして蓄積された結果を渡す必要があります:
(define power-is-fun
(lambda (x y acc)
(cond [(= y 0)
acc]
[(> y 0)
(power-is-fun x (- y 1) (* x acc))])))
このように呼び出すと、の初期値がacc
次1
のようになります(このためのヘルパー関数を作成できるため、1
毎回渡すことを覚えておく必要はありません)。
(power-is-fun 2 3 1)
> 8
再帰的プロシージャを末尾再帰に変換するためのいくつかの一般的なポインタ:
power-is-fun
に乗算を実行しましたが、末尾再帰バージョンでは、呼び出しpower-is-fun
はプロシージャを終了する前に発生する最後の処理です。ちなみに、整数のべき乗を実装するより速い方法があります。x
何度も何度も乗算するのではなくy
(これによりO(y)になります)、時間計算量がO(log y)であるアプローチがあります。
(define (integer-expt x y)
(do ((x x (* x x))
(y y (quotient y 2))
(r 1 (if (odd? y) (* r x) r)))
((zero? y) r)))
do
(私が知っている多くのSchemersがそうしているように)嫌いな場合は、明示的にテール再帰するバージョンがあります(let
もちろん、namedを使用して記述することもできます)。
(define (integer-expt x y)
(define (inner x y r)
(if (zero? y) r
(inner (* x x)
(quotient y 2)
(if (odd? y) (* r x) r))))
(inner x y 1))
(ちなみに、適切なスキームの実装では、両方のバージョンをまったく同じコードにマクロ展開する必要があります。また、オスカーのソリューションと同様に、ここでのみアキュムレータを使用しますr
(「結果」の略)。)
オスカーのアドバイスのリストは素晴らしいです。
反復(別名線形再帰)およびツリー再帰プロセスのより詳細な処理が必要な場合は、SICPの優れた処理をお見逃しなく:
http://mitpress.mit.edu/sicp/full-text/book/book-ZH-11.html#%_sec_1.2