Haskell 当使用bang模式时,IO monad是否变得严格?

Haskell 当使用bang模式时,IO monad是否变得严格?,haskell,io,monads,lazy-evaluation,syntactic-sugar,Haskell,Io,Monads,Lazy Evaluation,Syntactic Sugar,我希望看到以下代码片段: main = do let !x = [2,3,5,2,3,5,6,7,1,3,0,1] begin <- getCPUTime let !rx = reverse x end <- getCPUTime putStrLn $ "Calculation time: " ++ show (end - begin) ++ " ps." putStrLn $ "Result: " ++ show rx main=d

我希望看到以下代码片段:

main = do
    let !x = [2,3,5,2,3,5,6,7,1,3,0,1]
    begin <- getCPUTime
    let !rx = reverse x
    end <- getCPUTime
    putStrLn $ "Calculation time: " ++ show (end - begin) ++ " ps."
    putStrLn $ "Result: " ++ show rx
main=do
让我来!x=[2,3,5,2,3,5,6,7,1,3,0,1]

开始给定的特定代码示例生成相同的编译代码。如果您参加以下课程:

{-# LANGUAGE BangPatterns #-}

module Bang where

import System.CPUTime

main1 = do
    let !x = [2,3,5,2,3,5,6,7,1,3,0,1]
    begin <- getCPUTime
    let !rx = reverse x
    end <- getCPUTime
    putStrLn $ "Calculation time: " ++ show (end - begin) ++ " ps."
    putStrLn $ "Result: " ++ show rx

main2 = do
    let x = [2,3,5,2,3,5,6,7,1,3,0,1]
    begin <- x `seq` getCPUTime
    let rx = reverse x
    end <- rx `seq` getCPUTime
    putStrLn $ "Calculation time: " ++ show (end - begin) ++ " ps."
    putStrLn $ "Result: " ++ show rx
您将在转储的GHC内核中发现,
main1
main2
被编译为完全相同的代码,实际上被拉入一个单独的
main4
函数:

main1
main1 = main4 `cast` <Co:3>

main2
main2 = main4 `cast` <Co:3>
第一个会立即生成异常:

main = do
    print 1
    foo       -- EXCEPTION!
    print 2
第二个在执行时不执行任何操作,但如果您尝试仔细检查其结果,则会生成异常:

main = do
    print 1
    bar        -- does nothing
    print 2
    x <- bar   -- also does nothing
    print 3
    () <- bar  -- EXCEPTION!
    print 4

这就解释了它们的不同行为。

我认为它们应该是等价的,因为IO monad是严格的,即使我不完全理解
seq
上的GHC保证,这在某些情况下允许一些“重新排序”
pseq
更强大,应该保证代码顺序确实是大致上的求值顺序。请注意,WHNF不足以强制所有列表。如果您编写
seq x$return()
而不是
return$seq x()
,会怎么样?它们与
x`seq`return()
return(x`seq`())
完全相同,因此它们的行为就像
foo
bar
foo :: IO ()
foo = do
  let !x = undefined
  return ()

bar :: IO ()
bar = do
  let x = undefined
  return $ x `seq` ()
main = do
    print 1
    foo       -- EXCEPTION!
    print 2
main = do
    print 1
    bar        -- does nothing
    print 2
    x <- bar   -- also does nothing
    print 3
    () <- bar  -- EXCEPTION!
    print 4
bar = return (undefined `seq` ())
foo = undefined `seq` return ()