Today I’m going to look at a weird issue I encountered this past weekend while working on a DSL in Haskell.

I’ll start with the code. As this example uses Template Haskell, we need to have the source broken up into two files:

**Testa.hs**:

{-# LANGUAGE TemplateHaskell #-} module Testa where import Language.Haskell.TH someth = [| () |] unit = () mrIssue :: (Monad m) => b -> m b mrIssue = return

**Testb.hs**:

{-# LANGUAGE NoMonomorphismRestriction, TemplateHaskell #-} module Testb where import Testa g = $(someth) foo1 = mrIssue $(someth) f = () foo2 = mrIssue () h = unit foo3 = mrIssue unit

Now, if we fire up `ghci Testb.hs`

, we get the following:

$ ghci Testb.hs GHCi, version 6.10.4: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer ... linking ... done. Loading package base ... linking ... done. [1 of 2] Compiling Testa ( Testa.hs, interpreted ) [2 of 2] Compiling Testb ( Testb.hs, interpreted ) Loading package syb ... linking ... done. Loading package array-0.2.0.0 ... linking ... done. Loading package packedstring-0.1.0.1 ... linking ... done. Loading package containers-0.2.0.1 ... linking ... done. Loading package pretty-1.0.1.0 ... linking ... done. Loading package template-haskell ... linking ... done. Ok, modules loaded: Testb, Testa. *Testb> :t foo1 foo1 :: (Monad m) => m () *Testb> :t g :1:0: Ambiguous type variable `m' in the constraint: `Monad m' arising from a use of `g' at :1:0 Probable fix: add a type signature that fixes these type variable(s) *Testb>

Notice that, while we’re able to get the type for `foo1`

, for some reason `g`

is ill-typed with an ambiguous type variable in the constraint `Monad m`

. The only problem, of course, is that when we look at our source we *don’t see* any way in which the type for `g`

should have this constraint!

So maybe the problem is that `g`

needs a type signature. But if we go in and modify Testb.hs, giving it

```
```

```
g :: ()
g = $(someth)
```

then we get the following from ghci:

Testb.hs:10:7: Could not deduce (Monad m) from the context () arising from a use of `mrIssue' at Testb.hs:10:7-23 Possible fix: add (Monad m) to the context of the type signature for `g' In the expression: mrIssue ($someth) In the definition of `foo1': foo1 = mrIssue ($someth) Failed, modules loaded: Testa. *Testa>

So now it's upset about the type for `foo1`

. Fine. Let's give it a signature as well:

```
```g :: ()
g = $(someth)
foo1 :: (Monad m) => m ()
foo1 = mrIssue $(someth)

Now we get a new error from `ghci`

:

Testb.hs:11:0: Contexts differ in length (Use -XRelaxedPolyRec to allow this) When matching the contexts of the signatures for g :: () foo1 :: forall (m :: * -> *). (Monad m) => m () The signature contexts in a mutually recursive group should all be identical When generalising the type(s) for g, foo1 Failed, modules loaded: Testa.

If we add `RelaxedPolyRec`

to our list of `LANGUAGE`

extensions, the problem does, indeed, go away. In this case, we can even remove our type signature for `g`

*or* for `foo1`

, but not both -- we need to have at least one of them present.

Lastly, if we go back to our original source given above, but replace the signature for `mrIssue`

with

```
```mrIssue :: b -> IO b
mrIssue = return

then we can remove the `NoMonomorphismRestriction`

, and everything works just fine (we can `:t g`

and `:t foo1`

without any problems).

I'm entirely unsure of what's going on here. Any theories?

## 1 Comment