1

私は現在、楽しみのためにProject Eulerに取り組んでおり、練習にはHaskellを使用しています。ただし、問題が発生し、より小さな例を作成できないようです。そのため、コードは次のとおりです(プロジェクトオイラー232の場合)。

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))

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

これをロードしてここでsumBuild(7、5)を実行すると、例外が発生します。

*** Exception: Prelude.head: empty list

しかし、sumBuildを次のように変更すると:

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

また

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

その後、正常に動作します。

副作用がなく、2回の実行で異なる結果が生成されるため、これは私にとって本当に混乱します(少なくともそのような場合のようです)。ここでの問題は何ですか?

誰かがこのプログラムを最小限の実用的な例に編集することができれば、私は本当に感謝しています!

助けてくれてありがとう!

4

2 に答える 2

7

これがヒントです:

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

提案として、最上位宣言のタイプを常に明示的に指定してみてください。これにより、このようなバグを回避できます。

于 2012-04-07T16:02:00.030 に答える
6

問題は、 である の結果を乗算することによりlengthIntすべての計算をマシンサイズの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)))
于 2012-04-07T16:04:04.593 に答える