Re: overlapping instances and functional dependencies
Wolfgang Jeltsch has observed:
I have this code: class C a b c | a b -> c where f :: a -> b -> c
instance C a b c => C a (x,y,b) c where f a (_,_,b) = f a b
instance C a (a,c,b) c where f _ (_,c,_) = c ghci -fglasgow-exts -fallow-overlapping-instances compiles it without complaint but hugs -98 +o says: ERROR "ClassProblem.hs":7 - Instances are not consistent with dependencies *** This instance : C a (a,b,c) b *** Conflicts with : C a (b,c,d) e *** For class : C a b c *** Under dependency : a b -> c Can anyone tell me what the reason for this is and, maybe, how to avoid these problems with Hugs?
I believe it's helpful to think about this problem in terms of logical programming, and proceed in phases. Phase 1. The compiler sees the instances of a class C and compiles them into a database of instances. In Prolog terms, given the instances instance C a b c => C a (x,y,b) c instance C a (a,c,b) c the compiler asserts c(A,tuple(A,C,B),C,dict2). c(A,tuple(X,Y,B),C,dict1) :- c(A,B,C,_). In Haskell, lower-case type identifiers are variables and upper-case one are type constants. In Prolog, it's the other way around: lower-cased identifiers are constants and upper-cased are variables. I hope that won't cause too much confusion. I happen to have SWI-Prolog handy, in which I assert the above two facts. Phase 2. Suppose the compiler sees a type with a class constraint ``C Int (Int,Char,Bool) t'' The compiler can determine the appropriate instance by issuing a query: ?- bagof(Dict,c(int,tuple(int,char,bool),T,Dict),Dicts). Dict = _G158 T = char Dicts = [dict2] Yes In our case, only one instance matched, and we found the corresponding dictionary. If Dicts were a list of two or more dictionaries, we would have needed to choose the most specific, if any. Phase 1a. Before we get to Phase 2 however, we have to take care of one more problem. The class declaration specified a dependency: class C a b c | a b -> c which all members of that class must satisfy. The instances (which define the membership) must be consistent with the dependency "a b -> c". The consistency would be violated if there were two types "C a b c1" and "C a b c2" such that c1 /== c2. Thus we can check the consistency of the instances by searching for a counter-example: ?- c(A,B,C1,_), c(A,B,C2,_), \+ C1 == C2. A = _G151 B = tuple(_G151, _G153, tuple(_G151, _G158, _G302)) C1 = _G153 C2 = _G158 Yes Alas, in this case we found a counter-example: types C a (a,c,(a,c',d)) c C a (a,c,(a,c',d)) c' with c' /= c match some instance but contradict the functional dependency. Therefore, the compiler complaints.
Hi all With overlapping instances, I'm allowed class OK x y instance Functor f => OK (f x) (f y) instance Functor f => OK x (f y) but I'm not allowed class Bad x y z | x y -> z instance Functor f => Bad (f x) (f y) Bool instance Functor f => Bad x (f y) Int I don't quite see why. Naively, I imagine that if the OK instances are effectively prioritized, then Bad's rules for computing z from x and y could be similarly prioritized. Can anyone explain why this naive imagining is incorrect? Cheers Conor PS a more complicated, less contrived example is available on request
C T McBride writes: : | but I'm not allowed | | class Bad x y z | x y -> z | | instance Functor f => Bad (f x) (f y) Bool | | instance Functor f => Bad x (f y) Int | | I don't quite see why. Naively, I imagine that if the OK instances are | effectively prioritized, then Bad's rules for computing z from x and y | could be similarly prioritized. Can anyone explain why this naive | imagining is incorrect? Hi. The first instance decl includes instance Bad [()] [()] Bool and the second includes instance Bad [()] [()] Int which break the functional dependency because x and y do not uniquely determine z. But I suspect you already knew that, and were asking why the functional dependency feature is based on uniqueness constraints, not prioritised type-computation rules. I'm not sure of the original reason, but the uniqueness approach supports some neat tricks http://www.willamette.edu/~fruehr/haskell/evolution.html#fundep which the prioritised approach probably wouldn't. Regards, Tom
participants (3)
-
C T McBride -
oleg@pobox.com -
Tom Pledger