Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different results between interactive and compiled Haskell (Project Euler 20)

Tags:

haskell

I'm doing problem 20 on Project Euler - finding the sum of the digits of 100! (factorial, not enthusiasm).

Here is the program I wrote:

import Data.Char

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

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

I compiled it with ghc -o p20 p20.hs and executed it, getting only 0 on my command line.

Puzzled, I invoked ghci and ran the following line:

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

This returned the correct answer. Why didn't the compiled version work?

like image 268
Matthew Piziak Avatar asked Jun 24 '12 00:06

Matthew Piziak


1 Answers

The reason is the type signature

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

use

sumOfDigits :: Integer -> Int

and you will get the same thing as in GHCi (what you want).

Int is the type for machine word sized "ints" while, Integer is the type for mathematically correct, arbitrary precision Integers.

if you type

:t product [1..100]

into GHCi you will get something like

product [1..100] :: (Enum a, Num a) => a

that is, for ANY type that has instances of the Enum and Num type classes, product [1..100] could be a value of that type

product [1..100] :: Integer

should return 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 which is far bigger than your machine is likely to be able to represent as a word on your machine. Probably, because of roll over

product [1..100] :: Int

will return 0

given this, you might think

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

would not type check, because it has multiple possible incompatible interpretations. But, in order to be usable as a calculator, Haskell defaults to using Integer in situations like this, thus explaining your behavior.

For the same reason, if you had NOT given sumOfDigits an explicit type signature it would have done what you want, since the most general type is

sumOfDigits :: Show a => a -> Int
like image 98
Philip JF Avatar answered Sep 27 '22 21:09

Philip JF