2012-04-07 12 views
1

私は現在、プロジェクトオイラーを楽しく学び、練習にハスケルを使用しています。しかし、私は、問題が発生した、と私は小さい例を作り出すように見えることはできませんので、ここで(プロジェクトオイラー232用)コードは次のとおりです。Haskell:これがなぜ空リストの例外につながるのでしょうか?

buildNum (x, y) = multNum x y 1 [] 
    where multNum num mul exp s = if (num > 10^100) then s else multNum nNum mul nexp ns 
      where next = (num * mul) `div` exp 
       ns = num:s 
       top = next `mod` 10 
       nexp = exp * 10 
       nNum = num + nexp * top 

sumBuild (x, y) = (head (buildNum (x, y))) * length (buildNum (x, y)) 

ここに悪いスタイルを無視してください:)

を私はロードした場合これと、ここで、私は例外になるだろう(5、7)sumBuildを実行します。

*** Exception: Prelude.head: empty list 

しかし、私はにsumBuildを変更した場合:

sumBuild (x, y) = head (buildNum (x, y)) 

または

sumBuild (x, y) = length (buildNum (x, y)) 

これは正常に動作します。

これは私には本当に混乱しています。副作用がなく、2回の実行では異なる結果が出ます(少なくともそのようなケースであるようです)。ここでの問題は何ですか?

誰かがこのプログラムを最小限の作業例に編集できたら、本当に感謝しています!

ありがとうございました!

答えて

7

これがヒントです:常にトップレベルの宣言の明示的状態の種類を試してみ提案として

> :t sumBuild 
sumBuild :: (Int, Int) -> Int 
> let a = 7 :: Int 
> a > 10^100 
True 

。このようなバグを回避するのに役立ちます。

+0

ありがとうございます!悪いスタイルは本当に痛い...... –

6

問題がIntあるlengthの結果、と乗じて、あなたがオーバーフローにつながる、すべての計算は機械サイズIntタイプで行われるように強制することです。これを削除すると、デフォルトの任意サイズのIntegerタイプが代わりに使用されます。

タイプシグニチャとfromIntegralを追加すると、計算がIntegerで実行されるように強制すると、すべて正常に動作します。

buildNum :: (Integer, Integer) -> [Integer] 
buildNum (x, y) = -- same as before 

sumBuild :: (Integer, Integer) -> Integer 
sumBuild (x, y) = (head (buildNum (x, y))) * fromIntegral (length (buildNum (x, y))) 
関連する問題