使用`seq`并在haskell中打印

时间:2017-02-02 04:57:06

标签: debugging haskell io monads seq

我知道这有点棘手,但我想知道为什么它不起作用!

module Main where

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

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

虽然它的理想与

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

它与haskell的懒惰评估或副作用有关吗? https://hackhands.com/lazy-evaluation-works-haskell/

1 个答案:

答案 0 :(得分:4)

仅仅评估一些IO行动根本不做任何事情。您可以认为IO类似于Haskell 可以所做的所有可能的副作用事物的真正大的类型,即使它实际上没有实际实现。像这样:

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

此理论可视化中的IO构造函数之一是Sequence构造函数,其类型签名如下:

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

此构造函数用于为>>=类型实现IO

GHC内部是一个名为magicallyExecuteIO的神奇函数,其类型为IO a -> a,它协调每个动作以实际执行其相应的副作用。 (顺便提一下,这个函数有时也发音为unsafePerformIO。)GHC隐式调用程序magicallyExecuteIO函数结果的main,以及用GHCi编写的表达式。

但是,如果不使用magicallyExecuteIO,则评估其中一个IO构造函数(如PutStrLn)不会执行任何操作。在这个实现中,它将像任何其他数据构造函数一样工作:

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

(我已将其与Just包装在一起,以防止GHCi执行IO操作。)

当然,GHC的实际IO类型没有以这种方式实现,但这实际上只是一个实现细节。评估IO a值不会导致副作用发生,只会评估Maybe a值。只有magicallyExecuteIO可以做到这一点。