Haskell:为什么这会导致空列表异常?

zw3*_*324 1 haskell exception list side-effects

我目前正致力于Project Euler的乐趣,并使用Haskell进行练习.但是,我遇到了一个问题,我似乎无法生成一个更小的例子,所以这里是代码(对于项目euler 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))
Run Code Online (Sandbox Code Playgroud)

请忽略这里糟糕的风格:)

如果我加载它并在这里运行sumBuild(7,5),我会得到一个例外:

*** Exception: Prelude.head: empty list
Run Code Online (Sandbox Code Playgroud)

但是,如果我将sumBuild更改为:

sumBuild (x, y) = head (buildNum (x, y))
Run Code Online (Sandbox Code Playgroud)

要么

sumBuild (x, y) = length (buildNum (x, y))
Run Code Online (Sandbox Code Playgroud)

然后运行正常.

这对我来说真的很困惑,因为没有副作用,两次运行产生不同的结果(至少看起来是这样的情况).这里有什么问题?

如果有人可以将这个程序编辑成一个最小的工作示例,那么我真的很感激!

谢谢你的帮助!

Mat*_*nov 7

这是提示:

> :t sumBuild
sumBuild :: (Int, Int) -> Int
> let a = 7 :: Int
> a > 10^100
True
Run Code Online (Sandbox Code Playgroud)

作为建议,尝试始终明确声明顶级声明的类型.这有助于避免此类错误.


ham*_*mar 6

问题是,通过与结果相乘length,这是一个Int,你强迫所有的要与机器大小进行的计算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)))
Run Code Online (Sandbox Code Playgroud)