So lets assume you have two type classes defined like this:
{-# LANGUAGE MultiParamTypeClasses #-}
class F a c where f :: a -> c
class G c b where g :: c -> b
And then you want to define a new function h in a general way by using f and g.
h a = g (f a)
We know that this function has type a -> b so c is implicit in there. I want to leave it to the implementer of f and g what c might be. Haskell complains about this saying c is ambiguous.
Then as suggested by the error I turned on this extension:
{-# LANGUAGE AllowAmbiguousTypes #-}
Now it works! Nice.
I believe usually as a good software engineering practice, I want to write explicit specifications of my functions, to tell the compiler what I expect my functions should behave like. So that later compiler can complain about me not respecting what I set.
So I want to add the type of my function before it:
h :: (F a c, G c b) => a -> b
h a = g (f a)
And now the type ambiguousity error comes again... Why?
To summarize why does Haskell complain about this below piece of code? even if AllowAmbiguousTypes is explictly enabled. How to fix it while keeping an explicit function type definition? I know that removing the type definition of the function solves it but I don't want to underspecify things.
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
class F a c where f :: a -> c
class G c b where g :: c -> b
h :: (F a c, G c b) => a -> b
h a = g (f a)
And why doesn't Haskell complain about this?
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
class F a c where f :: a -> c
class G c b where g :: c -> b
h a = g (f a)
Error messages:
error:
* Could not deduce (G c0 b) arising from a use of `g'
from the context: (F a c, G c b)
bound by the type signature for:
h :: forall a c b. (F a c, G c b) => a -> b
The type variable `c0' is ambiguous
Relevant bindings include
h :: a -> b
* In the expression: g (f a)
In an equation for `h': h a = g (f a)
|
| h a = g (f a)
| ^^^^^^^
error:
* Could not deduce (F a c0) arising from a use of `f'
from the context: (F a c, G c b)
bound by the type signature for:
h :: forall a c b. (F a c, G c b) => a -> b
The type variable `c0' is ambiguous
Relevant bindings include
a :: a
h :: a -> b
* In the first argument of `g', namely `(f a)'
In the expression: g (f a)
In an equation for `h': h a = g (f a)
|
| h a = g (f a)
| ^^^