Thanks Ryan.

I'm always struggling with functional dependencies since to be honest - I don't really understand how the type inferer figures out all the types and I didn't take the time to study it yet. Your email will help me a bit further with this.

My functional dependency was c -> m v. It can't be m v -> c since for the same model and view type , you can have many controllers types.

On Sat, Feb 14, 2009 at 11:38 PM, Ryan Ingram <ryani.spam@gmail.com> wrote:
2009/2/13 Peter Verswyvelen <bugfact@gmail.com>:
> No the error I got was
> Could not deduce (Controller m v c)
> from the context (Controller m v c2)
>       arising from a use of `MVC' at NM8\GUI\PanZoom.hs:126:32-65
>     Possible fix:
>       add (Controller m v c) to the context of the constructor `MVC'
>     In the expression: MVC m v (PZC s z (unsafeCoerce c))
>     In the definition of `panZoomedMVC'':
>         panZoomedMVC' s z (MVC m v c) = MVC m v (PZC s z (unsafeCoerce c))
> I got this after adding the type signature of
> panZoomedMVC' :: (Controller m v c, PanZoomable z) =>
>                  State -> z -> MVC m v -> MVC m v

No function with the type signature of panZoomedMVC' can be called
(unless there is a functional dependency that uniquely determines c
from m and v).  It's ambiguous; there's no way to know which instance
to call.

GHC allows such a function to get an inferred type, but then when it
comes time to call it (and provide the Controller instance) or type
check it against a provided signature, it cannot resolve the ambiguity
and you get that error.

What is happening in this case is something along these lines:

1) Infer a type and constraints for panZoomedMVC':

Constraints:
  Controller t1 t2 t3
  PanZoomable t4

Type:
  State -> t4 -> MVC t1 t2 -> MVC t1 t2

2) Unify the inferred type signature with your provided signature

Constraints:
  Controller m v t3
  PanZoomable z

Type:
  State -> z -> MVC m v -> MVC m v

3) Verify that constraints are sufficient.  This fails, because the
use of Controller in the function (Controller m v t3) doesn't match
the use provided by your constraint (Controller m v c).

However, leaving out the type signature doesn't help you; it just
delays your problem.  Because of the ambiguity, panZoomedMVC' cannot
be called; you'll get the error at the callsite instead.

To solve this problem, either add a dummy argument that fixes "c", or
add a functional dependency or associated type to Controller that
fixes c based on m and v.  For example:

> data Proxy a = Proxy
> panZoomedMVC' :: (Controller m v c, PanZoomable z) =>
>                  Proxy c -> State -> z -> MVC m v -> MVC m v
> panZoomedMVC' _ s z mvc = ...

Then you can pass the proper "Proxy" when calling the function to make
the typechecker happy.

or

> class Controller m v c | m v -> c where ...

or

> class Controller m v where
>    type Control m v
>    ...

 -- ryan