Use `seq` and print in haskell

2019-07-30 00:10发布

问题:

I know that this is a little bit tricky but i wonder why it doesn't work!

module Main where

sillyDebug :: Int -> Int -> Int
sillyDebug x y =
    (print x) `seq` (x + y)

main :: IO ()
main = do
    print (sillyDebug 1 2)

while its ideal is the same as

sillyDebug = (trace (show x) False) `seq` (x + y)

Is it related to lazy evaluation or side effect in haskell? https://hackhands.com/lazy-evaluation-works-haskell/

回答1:

Merely evaluating some IO action doesn’t do anything at all. You can think of IO sort of like a really big sum type of all the possible side-effectful things Haskell can do, even if it isn’t actually implemented like that at all. Something like this:

data IO a where
  PutStrLn :: String -> IO ()
  ReadFile :: FilePath -> IO String
  ExitWith :: ExitCode -> IO a
  ...

One of the IO constructors in this theoretical visualization would be a Sequence constructor, with a type signature like this:

  Sequence :: IO a -> (a -> IO b) -> IO b

This constructor is used to implement >>= for the IO type.

Inside of GHC is a magical function called magicallyExecuteIO with type IO a -> a, which coordinates for each action to actually perform its corresponding side-effect. (Incidentally, this function is also sometimes pronounced unsafePerformIO.) GHC implicitly calls magicallyExecuteIO on the result of your program’s main function, as well as on expressions written in GHCi.

However, without using magicallyExecuteIO, evaluating one of the IO constructors like PutStrLn doesn’t do anything. In this implementation, it would just work like any other data constructor:

ghci> Just (PutStrLn "hello!")
Just (PutStrLn "hello!") :: Maybe (IO ())

(I’ve wrapped it with Just to prevent GHCi from running the IO action.)

Of course, GHC’s actual IO type isn’t implemented this way, but that’s really just an implementation detail. Evaluating an IO a value doesn’t cause a side-effect to happen any more than evaluating a Maybe a value does. Only magicallyExecuteIO can do that.