Type inference interferes with referential transparency

前端 未结 7 1295
醉酒成梦
醉酒成梦 2021-02-12 18:07

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

相关标签:
7条回答
  • 2021-02-12 18:34

    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:

    1. Perform all of the arithmetic using Integer operations and types and then convert the result to an Int.
    2. Perform all of the arithmetic using 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
    
    0 讨论(0)
提交回复
热议问题