I am running into a problem where GHC is not able to match Foo t
and Foo t0
, where it definitely looks to me like t ~ t0
. Here's a minimal example:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
data Foobar :: * -> * where
Foobar :: Foo t -> Foobar t
type family Foo a :: *
class Bar t where
f :: Foobar t
g :: Foo t
-- f = Foobar g
When uncommenting the last line, GHC complains:
Couldn't match expected type ‘Foo t’ with actual type ‘Foo t0’
NB: ‘Foo’ is a type function, and may not be injective
The type variable ‘t0’ is ambiguous
Relevant bindings include f :: Foobar t (bound at test.hs:13:3)
In the first argument of ‘Foobar’, namely ‘g’
In the expression: Foobar g
I understand that Foo
is not injective, but from my analysis GHC is never asked to come up with t
from Foo t
. It seems that the type t
is lost in Foobar g
, and so it can't match the inital Foo t
and the new Foo t0
. Is the context here not enough? Am I missing a case where f = Foobar g
could not yield the correct result?
Any help appreciated!
N.B.: ScopedTypeVariables
and explicit type signatures don't seem to help. Adding the constraint a ~ Foo t
and using a
instead as the type of g
in Foobar g
doesn't work either.
Looks a lot like: ambiguous type error when using type families, and STV is not helping. I considered using a Proxy
, but I feel like in this case GHC should be able to figure it out.
I understand that
Foo
is not injective, but from my analysis GHC is never asked to come up witht
fromFoo t
.
So, you realize the ambiguity. Let's make is explicit:
type instance Foo () = Bool
type instance Foo Char = Bool
instance Bar () where
-- I omit the declaration for f
g = True
instance Bar Char where
g = False
main = print (g :: Bool)
Your problem in f = Foobar g
is related to the ambiguity.
The crux is: the definition f = Foobar g
does not imply that g
much be picked in the same instance as f
. It could refer to a different instance!
Consider
show (x,y) = "(" ++ show x ++ ", " ++ show y ++ ")"
Above, the RHS uses of show
are from a different instance from the one where the LHS show
is.
In your f = Foobar g
line, GHC infers that g :: Foo t
where t
is the same index of the f
instance. However, that is not enough to select an instance for g
! Indeed, we might have Foo t ~ Foo t0
for some other t0
, hence g
might refer to the g
in the t0
instance, causing an ambiguity error.
Note that your code is rejected by GHC 8 even if the last line is commented out, because the type of g
is inherently ambiguous:
• Couldn't match expected type ‘Foo t’ with actual type ‘Foo t0’
NB: ‘Foo’ is a type function, and may not be injective
The type variable ‘t0’ is ambiguous
• In the ambiguity check for ‘g’
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
When checking the class method: g :: forall t. Bar t => Foo t
In the class declaration for ‘Bar’
We can follow the suggestion to make GHC 8 more lenient, like GHC 7. This will make your code type check, until we uncomment the last line.
• Couldn't match expected type ‘Foo t’ with actual type ‘Foo t0’
NB: ‘Foo’ is a type function, and may not be injective
The type variable ‘t0’ is ambiguous
This is the same error you saw in GHC 7.
In GHC 8, we have another luxury: we can explicitly choose the t
for g
as follows:
class Bar t where
f :: Foobar t
f = Foobar (g @ t)
g :: Foo t
This requires a few more extensions to be turned on, of course. In GHC 7, you need a proxy to be able to select an instance unambiguously.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With