To avoid this problem, you can use type families instead:
{-
Typical families are nice. Use family types when you can!
I assume that your error is related to the fact that ghc can output f :: Int -> Float from f :: Foo Int a => Int -> a and the definition of your class and instances, but cannot output g :: Foo Int a => Int -> a from g:: Int -> Float .
It is convenient to think of constraints as the secret parameter of a dictionary for a function. There is a characteristic but limited polymorphism in f, which is absent in g.
I find it helpful to note that ghci gives us almost the same error message as if we were trying to determine
j :: Int -> Float j = undefined k :: Eq a => Int -> a k = j
Obviously, this should not work, because we know that k must be a proactive polymorphism in the second argument. ghc attempts to map the type Int -> a to Int -> Float and fails, stating that it cannot infer a ~ Float from the context of Eq a , although there is an instance of Eq Float . In your example, he says that he cannot get a ~ Float out of the context of Foo Int a , although there is an instance for Foo Int Float . I understand that we can conclude that for a there is only one possible type, but by creating a class and an instance for Foo, you defined the relation and approved it as a functional dependency. This is not the same as defining a function (therefore type families solve the problem - it defines a function).
ghc also complains when you write
aconst :: (Foo Int a) => a aconst = 0.0
or even
anotherconst :: (Foo Int a) => a anotherconst = 0.0::Float
always, because it cannot be matched with the limited polymorphic a , which is required for the specific type that you gave it ( Fractional a or Float ).
Do you want to
forall a.Foo Int a
- The same type as Float , but it is not. There is only one type that satisfies forall a.Foo Int a , it Float , so ghci can take f::forall a.(Foo Int a)=>a->Float and output (using the dictionary for Foo) that f::Int->Float , but you expect ghci to take Float and find the notification it forall a.Foo Int a , but there is no dictionary for Float, it's a type, not a type. ghci can do this in one way, but not in another.
Given a point about local information is that ghc will have to use the definition of Foo and the instance you made to deduce that Float can be rewritten forall a.(Foo Int a) , and that at this point in the ghc compilation without using global information because itโs just trying to make a match. I want to say that Float matches forall a.(Foo Int a) , but forall a.(Foo Int a) doesn't match Float , in the sense that "this" matches the pattern (x:xs) , but (x:xs) does not match the "this" pattern.