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

时间:2012-06-24 00:50:25

标签: haskell

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

这是我写的程序:

import Data.Char

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

sumOfDigits :: Int -> Int
sumOfDigits n = sum $ map digitToInt (show n)

我使用ghc -o p20 p20.hs对其进行了编译并执行了它,只在我的命令行中获取0

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

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

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

1 个答案:

答案 0 :(得分:15)

原因是类型签名

sumOfDigits :: Int -> Int
sumOfDigits n = sum $ map digitToInt (show n)

使用

sumOfDigits :: Integer -> Int

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

Int是机器字大小的“整数”的类型,而Integer是数学上正确的,任意精度Integers的类型。

如果您输入

:t product [1..100]

进入GHCi,你会得到像

这样的东西
product [1..100] :: (Enum a, Num a) => a

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

product [1..100] :: Integer

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

product [1..100] :: Int

将返回0

鉴于此,您可能会想到

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

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

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

sumOfDigits :: Show a => a -> Int