我在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]))
这返回了正确的答案。为什么编译版本不起作用?
答案 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