与えられた数の階乗を計算する2つの関数があります。最初のもの、!
は、アキュムレータスタイルを使用します。第2のfact
は、自然再帰を使用します。第31、HtDPの下部に再帰とアキュムレータのスタイルの比較
(define (! n0)
(local (;; accumulator is the product of all natural numbers in [n0, n)
(define (!-a n accumulator)
(cond
[(zero? n) accumulator]
[else (!-a (sub1 n) (* n accumulator))])))
(!-a n0 1)))
と
(define (fact n)
(cond
[(= 0 n) 1]
[else (* n (fact (- n 1)))]))
は自然に再帰バージョンは、多くの場合のように高速であれば、アキュムレータのバージョンよりも高速ではありませんが、理由を述べていないと述べています。私はこれについていくつかの読書をしましたが、答えは'tail call optimization/elimination'だと思われますが、Wikipediaの記事は、少なくともパフォーマンスに関してHtDPが言っていることとは異なると思われます。なぜこれはそうですか?
再帰的なスタイルが高速です。自宅では、アキュムレータスタイルがより高速です。どのスタイルが一般的に好まれるかについての選択を導く一般的なヒューリスティックはありませんか?アキュムレータスタイルはメモリ効率が良いと私は理解していますが、ディスカッションをパフォーマンスだけに限定すれば、少なくとも私にとってはより良い選択であることは不明です。
私はもう少しこのことについて考えてきた、と一般的なケースアキュムレータスタイルの再帰の優位性にWikipediaの記事を左右する必要があります。スタック/ヒープ領域の使用量を減らすだけでなく、メモリアクセスは常にレジスタアクセスの背後にあるため、マルチコアがここに来るとより明白になります。それでも、HtDPは、すべてのケースで実際のテストが必要であることを証明しています。
洞察をいただきありがとうございます。それは非常によく説明されました。理想的なのは、誰かが64ビットWindows版のRacketで検証できるかどうかです。 – Greenhorn