交互式和编译的Haskell之间的不同结果(Project Euler 20)

Mat*_*iak 7 haskell

我在Project Euler上做了问题20 - 找到100的数字之和!(阶梯,而不是热情).

这是我写的程序:

import Data.Char

main = print $ sumOfDigits (product [1..100])

sumOfDigits :: Int -> Int
sumOfDigits n = sum $ map digitToInt (show n)
Run Code Online (Sandbox Code Playgroud)

我编译它ghc -o p20 p20.hs并执行它,只0在我的命令行上.

困惑,我调用ghci并运行以下行:

sum $ map Data.Char.digitToInt (show (product [1..100]))

这返回了正确的答案.为什么编译版本不起作用?

Phi*_* JF 15

原因是类型签名

sumOfDigits :: Int -> Int
sumOfDigits n = sum $ map digitToInt (show n)
Run Code Online (Sandbox Code Playgroud)

使用

sumOfDigits :: Integer -> Int
Run Code Online (Sandbox Code Playgroud)

你将得到与GHCi相同的东西(你想要的).

Int机器字大小为"整数" Integer的类型,而数学正确,任意精度的类型Integers.

如果你输入

:t product [1..100]
Run Code Online (Sandbox Code Playgroud)

进入GHCi你会得到类似的东西

product [1..100] :: (Enum a, Num a) => a
Run Code Online (Sandbox Code Playgroud)

也就是说,对于具有Enum和Num类型类实例的任何类型,product [1..100]可以是该类型的值

product [1..100] :: Integer
Run Code Online (Sandbox Code Playgroud)

应该返回远大于您的机器可能在您的机器上表示为单词的93326215443944152681699238856266792963895217599993816214685929638952175991832299156089414639761565182862536979208272237582511852109168640000000000000000000000000000.可能是因为翻身

product [1..100] :: Int
Run Code Online (Sandbox Code Playgroud)

将返回0

考虑到这一点,你可能会想

sum $ map Data.Char.digitToInt (show (product [1..100]))
Run Code Online (Sandbox Code Playgroud)

不会打字检查,因为它有多种可能不兼容的解释.但是,为了可以用作计算器,Haskell默认Integer在这种情况下使用,从而解释你的行为.

出于同样的原因,如果你没有给出sumOfDigits一个明确的类型签名,它就会做你想要的,因为最常见的类型是

sumOfDigits :: Show a => a -> Int
Run Code Online (Sandbox Code Playgroud)