使用 bang 模式时,IO monad 会变得严格吗?

Does IO monad become strict when bang pattern is used?

我期待以下代码片段:

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

这是真的吗?如果 xrx 在第一个版本中当 "needed" 计算为 WHNF 时,这是错误的。

顺便说一句,我想提出一个用于深度评估的语法糖,命名为"double bang pattern"。

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

{-# 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 版本 8.6.5):

stack ghc -- -dsuppress-all -dsuppress-uniques -ddump-simpl -fforce-recomp -O2 Bang.hs

你会在转储的GHC核心中发现main1main2被编译成完全相同的代码,实际上被拉出到一个单独的main4函数中:

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

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

但是,一般来说,let !x = ... 构造并不完全等同于使用 let x = ... 后跟 x `seq` y。例如下面两个IO动作是不同的:

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

我相信在脱糖之后,barfoo等同于:

bar = return (undefined `seq` ())
foo = undefined `seq` return ()

这解释了他们不同的行为。