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 ()