次のようなhaskell式を考えてみましょう:(重要な例、明白な方法が何であるかを教えてはいけません!;)
toBits :: Integral a => a -> [Bool]
toBits 0 = []
toBits n = x : toBits m where
(m,y) = n `divMod` 2
x = y /= 0
この関数は末尾再帰ではないため、次のように書くこともできます。
toBits :: Integral a => a -> [Bool]
toBits = toBits' [] where
toBits' l 0 = l
toBits' l n = toBits (x : l) m where
(m,y) = n `divMod` 2
x = y /= 0
(この表現には何も問題がないことを願っています)
私が聞きたいのは、これらの解決策のどれが優れているかということです。最初のソリューションの利点は、部分的に非常に簡単に評価できることです(Haskellは最初のソリューションで停止する:
必要がないため)が、2番目のソリューションは(明らかに)末尾再帰ですが、私の意見では完全に評価する必要がありますあなたが何かを出すことができるまで。
これの背景は私のBrainfuckパーサー(私の最適化の質問を参照)です。これは非常に醜い(さまざまなreverse
命令... ooh)実装されていますが、最初の方法で簡単に実装できます-これを「セミテール再帰」の方法と呼びましょう。