LLR2006: HaskellでCollatz予想に挑戦

お待たせしました!
キミならどう書く 2.0 ROUND 2の開催です!!

今回のLL Ringでは「LLで関数プログラミング」のセッションをはじめとし,関数型言語の活躍が期待されます.そこで,前哨戦にも関数型のお題を用意しました.

お題は「Collatz予想」(角谷予想,3x+1問題)についての問題です.

キミならどう書く 2.0 - ROUND 2 -

面白そうなので、Haskellでこの問題に挑戦してみました。
う〜ん。もっとコンパクトに書きたかったのですが、ダメでした。
まず、インデントのレベルが深すぎます。ガードとlet...inとcase...of...を組み合わせて使うと、すぐにこんな感じになってしまいます。
あと、無駄な計算もあるので何とかしたいですね。これについては、計算結果の状態をハッシュか何かで保持しておけば、解決できそうです。
時間があれば、改良版を考えてみたいと思います。

import System

main :: IO ()
main = do
    args <- getArgs
    putStrLn $ show $ h (read $ head args)

h :: Int -> Int
h n = h' n n 0
    where
        h' :: Int -> Int -> Int -> Int
        h' n maxi maxv
            | n == 1    = maxi + 1
            | otherwise =
                let r = collatz n 0 in
                    case (r > maxv) of
                        True  -> h' (n - 1) (n - 1) r
                        False -> h' (n - 1)  maxi   maxv

        collatz :: Int -> Int -> Int
        collatz n c
            | n == 1    = c + 1
            | even n    = collatz (n `div` 2) (c + 1)
            | otherwise = collatz (3 * n + 1) (c + 1)

以下は実行結果です。

% ghc collatz.hs
% ./a.out 100
97

追記 (2006/07/13 19:30)

問題の読み間違いをしていて、プログラムが間違っていたので、修正しました。