
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
2009/2/13 Peter Verswyvelen
: 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