Opened 6 years ago
Last modified 6 years ago
#5858 closed bug
type inference of an OverloadedString for a class instance with type parameters — at Version 3
Reported by: | GregWeber | Owned by: | |
---|---|---|---|
Priority: | normal | Milestone: | |
Component: | Compiler | Version: | 7.4.1 |
Keywords: | Cc: | greg@… | |
Operating System: | Unknown/Multiple | Architecture: | Unknown/Multiple |
Type of failure: | None/Unknown | Test Case: | |
Blocked By: | Blocking: | ||
Related Tickets: | Differential Rev(s): | ||
Wiki Page: |
Description (last modified by )
We have some code in Yesod:
class RedirectUrl master a where -- | Converts the value to the URL and a list of query-string parameters. toTextUrl :: a -> GHandler sub master Text instance t ~ Text => RedirectUrl master (Route master, [(t, t)]) where toTextUrl (u, ps) = do r <- getUrlRenderParams return $ r u ps
When I use it in my application, I am required to give an annotation to the overloaded strings. If I don't:
redirect $ (SearchR, [("foo", "bar")])
I end up with this error message:
No instance for (RedirectUrl Search (Route Search, [(t0, t1)])) arising from a use of `redirect' Possible fix: add an instance declaration for (RedirectUrl Search (Route Search, [(t0, t1)])) In the expression: redirect In the expression: redirect $ (SearchR, [("foo", "bar")]) In an equation for `getFoodsr23R': getFoodsr23R foodId = redirect $ (SearchR, [("foo", "bar")])
I would be ok with having to type annotate if instead of the compiler suggesting I declare an entire new instance the compiler instead suggested that I annotate my overloaded strings.
However, in trying to reproduce this program in a simpler setting, it seems to normally perform the OverloadedStrings
inference without any issue. This works just fine:
{-# LANGUAGE OverloadedStrings, NoMonomorphismRestriction, FlexibleInstances, GADTs #-} module InferOverloaded where import Data.Text class InferOverloaded a where infer :: a -> a data Data = Data String instance t ~ Text => InferOverloaded (Data, [(t,t)]) where infer = id foo = infer (Data "data", [("overloaded", "strings")])
Change History (3)
comment:1 Changed 6 years ago by
Cc: | greg@… added |
---|
comment:3 Changed 6 years ago by
Description: | modified (diff) |
---|---|
difficulty: | → Unknown |
Here's why it your last example works: GHC infers this type for foo
:
foo :: forall t t1. (Data.String.IsString t1, Data.String.IsString t, InferOverloaded (Data, [(t, t1)])) => (Data, [(t, t1)])
Notice that
- There is nothing to force "overloaded" and "strings" to have the same type, so they get types t, t1 respectively.
- Hence the instance does not get used
- GHC instead defers solving the constraint to the call site, in the hope that it may by then be clearer what t, t1 are.
One way to get the un-annotated behaviour you want might be this:
instance (t1 ~ Text, t2 ~ Text) => InferOverloaded (Data, [(t1,t2)] where infer = id
About your suggestion about error messages, I suppose that in the situation where giving more type information at the call site would pick a valid instance, we could suggest that. I can see where to do this. Could you supply a small test case that exhibits the behaviour? (Not depending on Data.Text
.)
Thanks
Simon
I am using 7.4 Haven't tried 7.0 yet.