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