What is the precise promise/guarantee the Haskell language provides with respect to referential transparency? At least the Haskell report does not mention this notion.
C
I thought of something which might help clarify things...
The expression mod (7^7^7) 5
has type Integral a
so there are two common ways to convert it to an Int
:
Integer
operations and types and then convert the result to an Int
.Int
operations.If the expression is used in an Int
context Haskell will perform method #2. If you want to force Haskell to use #1 you have to write:
fromInteger (mod (7^7^7) 5)
This will ensure that all of the arithmetic operations will be performed using Integer
operations and types.
When you enter he expression at the ghci REPL, defaulting rules typed the expression as an Integer
, so method #1 was used. When you use the expression with the !!
operator it was typed as an Int
, so it was computed via method #2.
My original answer:
In Haskell the evaluation of an expression like
(7^7^7`mod`5`mod`2)
depends entirely on which Integral
instance is being used, and this is something that every Haskell programmer learns to accept.
The second thing that every programmer (in any language) has to be aware of is that numeric operations are subject to overflow, underflow, loss of precision, etc. and thereby the laws for arithmetic may not always hold. For instance, x+1 > x
is not always true; addition and multiple of real numbers is not always associative; the distributive law does not always hold; etc. When you create an overflowing expression you enter the realm of undefined behavior.
Also, in this particular case there are better ways to go about evaluating this expression which preserves more of our expectation of what the result should be. In particular, if you want to efficiently and accurately compute a^b mod c you should be using the "power mod" algorithm.
Update: Run the following program to see how the choice of Integral
instance affects the what an expression evaluates to:
import Data.Int
import Data.Word
import Data.LargeWord -- cabal install largeword
expr :: Integral a => a
expr = (7^e `mod` 5)
where e = 823543 :: Int
main :: IO ()
main = do
putStrLn $ "as an Integer: " ++ show (expr :: Integer)
putStrLn $ "as an Int64: " ++ show (expr :: Int64)
putStrLn $ "as an Int: " ++ show (expr :: Int)
putStrLn $ "as an Int32: " ++ show (expr :: Int32)
putStrLn $ "as an Int16: " ++ show (expr :: Int16)
putStrLn $ "as a Word8: " ++ show (expr :: Word8)
putStrLn $ "as a Word16: " ++ show (expr :: Word16)
putStrLn $ "as a Word32: " ++ show (expr :: Word32)
putStrLn $ "as a Word128: " ++ show (expr :: Word128)
putStrLn $ "as a Word192: " ++ show (expr :: Word192)
putStrLn $ "as a Word224: " ++ show (expr :: Word224)
putStrLn $ "as a Word256: " ++ show (expr :: Word256)
and the output (compiled with GHC 7.8.3 (64-bit):
as an Integer: 3
as an Int64: 2
as an Int: 2
as an Int32: 3
as an Int16: 3
as a Word8: 4
as a Word16: 3
as a Word32: 3
as a Word128: 4
as a Word192: 0
as a Word224: 2
as a Word256: 1