与えられた数の階乗を計算する2つの関数があります。最初のもの!
は、アキュムレータスタイルを使用します。2番目の、fact
は、自然再帰を使用します。
(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)))]))
セクション31の下部で、HtDPは、自然再帰バージョンは、アキュムレータバージョンよりも高速ではないにしても、多くの場合高速であると述べていますが、その理由については述べていません。これについて読んだところ、答えは「末尾呼び出しの最適化/削除」のようですが、ウィキペディアの記事は、少なくともパフォーマンスに関しては、HtDPの発言と矛盾しているようです。なんでそうなの?
職場では、再帰的なスタイルの方が高速です。自宅では、アキュムレータスタイルの方が高速です。どのスタイルが一般的に好まれるのかを選択するための一般的なヒューリスティックはありませんか?アキュムレータスタイルの方がメモリ効率が高いことは理解していますが、議論をパフォーマンスだけに限定すると、少なくとも私にはわかりません。どちらがより良い選択です。
私はこれについてもう少し考えましたが、一般的な場合のアキュムレータスタイルの再帰の優位性に関するウィキペディアの記事を支持する必要があります。スタック/ヒープスペースの使用量を削減するだけでなく、メモリアクセスは常にレジスタアクセスの背後にあり、マルチコアがここにあることをより明確にすることができます。それでも、HtDPは、すべての場合に実際のテストが必要であることを証明しています。