Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a bang pattern on unit really needed here?

While hacking Stack, I found this:

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

HLint says: “remove that thing”. But I don't think it's a typo. Is there any reason to ever write !()?

like image 943
Mark Karpov Avatar asked Dec 10 '15 11:12

Mark Karpov


1 Answers

If in doubt (and not in a hurry) consult the specification.

The expression

do !() <- foo
   bar

desugars to

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

By the rules for function definition this is equivalent to

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

Now the rules for bang patterns are in the GHC user guide, as it is non-standard haskell. there we find that we can rewrite this into

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

Now 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. Or x is not ⊥, and the seq equals its second argument. In either case, the above code is identical to

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

which, tracing back these steps, is equivalent to

do () <- foo
   bar

So in conclusion: There is no reason to do that in a do expression.

There is, however, a difference between

let () = foo
in bar

(where foo will never be evaluated) and

let !() = foo
in bar

because let-expressions have special provisions in the semantics for bang patterns.

like image 200
Joachim Breitner Avatar answered Sep 28 '22 03:09

Joachim Breitner