[Haskell-cafe] Weird defaulting on newEmptyTMVar

Ian Denhardt ian at zenhack.net
Sun Feb 10 19:04:26 UTC 2019

Quoting Ruben Astudillo (2019-02-09 22:24:52)
> Dear list
> Playing on ghci I encountered the following type
>     GHCi, version 8.6.3: http://www.haskell.org/ghc/  :? for help
>     Prelude> :m +Control.Concurrent.STM
>     Prelude Control.Concurrent.STM> var1 <- atomically $ newEmptyTMVar
>     Prelude Control.Concurrent.STM> :t var1
>     var1 :: TMVar GHC.Types.Any
>     Prelude Control.Concurrent.STM>
> I would think `var1 :: TMVar a` as the documentation says it should.
> Reading on `GHC.Types` `Any` seems to be a type family related to some
> laws on `unsafeCoerce`. Can anybody explain me why is this sensible
> defaulting and how to obtain the expected result?

There's a fine distinction here: The docs don't specify:

`var1 :: forall a. TMVar a`

but rather:

    `newEmptyTMVar :: forall a.  STM (TMVar a)`.

I've inserted the explicit foralls for clarity.

Suppose the behavior was as you expected (I'll use regular MVars just
for brevity):

    var <- newEmptyMVar
    ghci> :t var
    var :: forall a. MVar a

Then, because the variable is polymorphic, we should be able to do:

    putMVar var "Hello"

and, we should also be able to do:

    putMVar var 43

But this is clearly unsafe, because we've put values of two different
types in the same MVar!

In a full program, what would most likely happen is, the first time GHC
sees a use of putMVar, it constrains the type variable to match that
type. In something like this:

        var <- newEmptyMVar
        putMVar var "hello"

On the second line, GHC constrains the `a` type variable to be `String`,
and so marks that particular use of `newEmptyMVar` as having been used
at type `IO (MVar String)`.

If we don't actually do anything with the MVar, like:

    someAction = do
        var <- newEmptyMVar
        return var

then `someAction` is inferred to be of type `forall a. IO (MVar a)`,
just like `newEmptyMVar` itself. The constraining will happen wherever
the MVar actually ends up getting used.

But, in the REPL, we're in this weird state where we have access to the
variable and can as what it's type is, but then things can happen
*later* that will force GHC to change the answer.


More information about the Haskell-Cafe mailing list