haskell / haskell/error-messages
Better suggestion for ambiguous type variables in certain situations
- 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.