2012-06-24 16 views
7

Estoy haciendo el problema 20 en el Proyecto Euler: ¡encuentro la suma de los dígitos de 100! (factorial, no entusiasmo).Diferentes resultados entre Haskell interactiva y compilada (Proyecto Euler 20)

Aquí está el programa que escribí:

import Data.Char 

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

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

compilé con ghc -o p20 p20.hs y ejecuté, recibiendo sólo 0 en mi línea de comandos.

Desconcertado, me invoca ghci y se pasó la siguiente línea:

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

Esta volvieron la respuesta correcta. ¿Por qué la versión compilada no funcionó?

Respuesta

15

La razón es el tipo de firma

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

uso

sumOfDigits :: Integer -> Int 

y obtendrá el mismo que en GHCi (lo que quiere).

Int es el tipo de máquina de tamaño de palabra "ints" mientras que Integer es el tipo matemáticamente correcto, precisión arbitraria Integers.

si escribe

:t product [1..100] 

en GHCi usted consigue algo como

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

que es, para cualquier tipo que tiene instancias de las clases tipo de enumeración y Num, product [1..100] podría ser un valor de ese tipo

product [1..100] :: Integer 

deberían volver 93326215443944152681699238856266700490715 968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 que es mucho más grande de lo que su máquina probablemente pueda representar como palabra en su máquina. Probablemente, debido a rodar sobre

product [1..100] :: Int 

devolverá 0

Ante esto, se podría pensar

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

no habría tipo de comprobación, ya que tiene múltiples interpretaciones posibles incompatibles. Pero, para ser utilizable como una calculadora, Haskell usa de manera predeterminada Integer en situaciones como esta, explicando así su comportamiento.

Por la misma razón, si no hubiera dado sumOfDigits un tipo de firma explícita lo habría hecho lo que quiere, ya que el tipo más general es

sumOfDigits :: Show a => a -> Int 
Cuestiones relacionadas