这里真的需要单位的爆炸模式吗?

Is a bang pattern on unit really needed here?

在破解 Stack 时,我发现 this:

!() <- atomicModifyIORef (eoExeCache eo) $ \m' ->
    (Map.insert name epath m', ())

HLint 说:“删除那个东西”。但我不认为这是一个错字。有什么理由写 !()?

如有疑问(并不着急)请咨询 specification

表达式

do !() <- foo
   bar

desugars

let ok !() = bar
    ok _   = fail ..
in foo >>= ok

rules for function definition 这相当于

let ok = \x -> case x of !() -> bar
                         _   -> fail ...
in foo >>= ok

现在 rules for bang patterns 在 GHC 用户指南中,因为它是非标准的 haskell。在那里我们发现我们可以将其重写为

let ok = \x -> x `seq` (case x of () -> bar
                                  _  -> fail ...)
in foo >>= ok

现在seq is defined in terms of its argument being ⊥ or not. So either x is ⊥, but then the second argument to seq, namely the case x of ... is also ⊥ according to the semantics of pattern matching。或者 x 不是 ⊥,并且 seq 等于它的第二个参数。在任何一种情况下,上面的代码都等同于

let ok = \x -> case x of () -> bar
                         _  -> fail ...
in foo >>= ok

追溯这些步骤,相当于

do () <- foo
   bar

总而言之:没有理由在 do 表达式中这样做。

但是,

let () = foo
in bar

(其中 foo 永远不会被评估)和

let !() = foo
in bar

因为 let 表达式在 semantics for bang patterns.

中有特殊规定