haskell / haskell/error-messages

Better suggestion for ambiguous type variables in certain situations

Open
#7 6 comments 2 reactions 0 assignees View on GitHub
status:Composing error message tool:GHC type:error-message
Dominant language
No language data
Stars
76
Forks
19
PR merge metrics
No merged PRs in 30d

Description

In [this recent stackoverflow question](https://stackoverflow.com/q/68380080/15207568) the asker presents the following piece of code (I have slightly adapted it) which gives an unhelpful error message:

```haskell
module Test where

import Data.Aeson
import Data.Text (Text, unpack, pack)
import Text.Ginger
import Data.Functor.Identity
import Data.Function

mapLeft f (Left x) = Left (f x)
mapLeft _ (Right x) = Right x

tshow = pack . show

renderTemplate :: ToJSON c => Text -> c -> Either Text Text
renderTemplate template ctx = do
tpl <- tplEither
let ctxGVal = rawJSONToGVal $ toJSON ctx
let r = easyRender ctxGVal tpl
return r
where
tplEither :: Either Text (Template SourcePos)
tplEither = parseGinger nullResolver Nothing (unpack template) & runIdentity & mapLeft tshow
nullResolver :: IncludeResolver Identity
nullResolver = const $ return Nothing
```

The error message is:

```
Ginger.hs:18:11: error:
• Could not deduce (ToGVal
(Run SourcePos (Control.Monad.Trans.Writer.Lazy.Writer Text) Text)
(GVal m0))
arising from a use of ‘easyRender’
from the context: ToJSON c
bound by the type signature for:
renderTemplate :: forall c.
ToJSON c =>
Text -> c -> Either Text Text
at Ginger.hs:14:1-59
The type variable ‘m0’ is ambiguous
These potential instance exist:
instance ToGVal m (GVal m) -- Defined in ‘Text.Ginger.GVal’
• In the expression: easyRender ctxGVal tpl
In an equation for ‘r’: r = easyRender ctxGVal tpl
In the expression:
do tpl <- tplEither
let ctxGVal = rawJSONToGVal $ toJSON ctx
let r = easyRender ctxGVal tpl
return r
|
18 | let r = easyRender ctxGVal tpl
| ^^^^^^^^^^^^^^^^^^^^^^
```

It is large but it is fairly clear what the issue is: `m0` is ambiguous. There is even a potential instance listed, but that is not really actionable unless the programmer understands that the `m` in that instance needs to be `Run SourcePos (Control.Monad.Trans.Writer.Lazy.Writer Text) Text` which can be hard to see for less experienced programmers.

In such ambiguous cases where there is only one potential instance then it might make sense to give a more elaborate explanation about how that instance could be used. In this case it could be:

```
These potential instance exist:
instance ToGVal m (GVal m) -- Defined in ‘Text.Ginger.GVal’
To use this instance you can add a type signature to `ctxGVal`:
ctxGVal :: GVal (Run SourcePos (Control.Monad.Trans.Writer.Lazy.Writer Text) Text)
```

Or perhaps it is easier (for GHC) to suggest `TypeApplications`:

```
To use this instance you can use `TypeApplications`:
easyRender @_ @_ @(GVal (Run SourcePos (Control.Monad.Trans.Writer.Lazy.Writer Text) Text))
```

This brings up another issue which is that GHC sometimes shows names that are not in scope in its output. In this case you will get a second error that is probably understandable but not very nice:

```
Ginger.hs:21:34: error:
Not in scope:
type constructor or class ‘Control.Monad.Trans.Writer.Lazy.Writer’
No module named ‘Control.Monad.Trans.Writer.Lazy’ is imported.
|
21 | let r = easyRender (ctxGVal :: Control.Monad.Trans.Writer.Lazy.Writer) tpl
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```

It gets even worse if the `transformers` package is not exposed, then it will show `transformers-0.5.6.2:Control.Monad.Trans.Writer.Lazy.Writer` which is not valid Haskell syntax at all.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.