text: oleg at pobox.com writes: > > Martin Sulzmann wrote: > > > Let's consider the general case (which I didn't describe in my earlier > > email). > > > > ... > > > Sorry, I left out the precise definition of the rank function > > in my previous email. Here's the formal definition. > > > > rank(x) is some positive number for variable x > > > > rank(F t1 ... tn) = 1 + rank t1 + ... + rank tn > > > > where F is an n-ary type constructor. > > > > rank (f t) = rank f + rank t > > > > f is a functor variable > > Yes, I was wondering what rank means exactly. But now I do > have a problem with the criterion itself. The following simple and > quite common code > > > newtype MyIOState a = MyIOState (Int -> IO (a,Int)) > > > > instance Monad MyIOState where > > return x = MyIOState (\s -> return (x,s)) > > > > instance MonadState Int MyIOState where > > put x = MyIOState (\s -> return ((),x)) > > > becomes illegal then? Indeed, the class |MonadState s m| has a > functional dependency |m -> s|. In our case, > m = MyIOState, rank MyIOState = 1 > s = Int rank Int = 1 > and so rank(m) > rank(s) is violated, right? > > The additional conditions I propose are only necesssary once we break the Bound Variable Condition. Recall: The Bound Variable Condition (BV Condition) says: for each instance C => TC ts we have that fv(C) subsetof fv(ts) (the same applies to (super)class declarations which I leave out here). The above MonadState instance does NOT break the BV Condition. Hence, everything's fine here, the FD-CHR results guarantee that type inference is sound, complete and decidable. Though, your earlier example breaks the BV Condition. > class Foo m a where > foo :: m b -> a -> Bool > > instance Foo m () where > foo _ _ = True > > instance (E m a b, Foo m b) => Foo m (a->()) where > foo m f = undefined > > class E m a b | m a -> b where > tr :: m c -> a -> b > instance E m (() -> ()) (m ()) In the second instance, variable b appears only in the context but not in the instance head. But variable b is "captured" by the constraint E m a b where m and a appear in the instance head and we have that class E m a b | m a -> b. We say that this instance satisfies the Weak Coverage Condition. The problem is that Weak Coverage does not guarantee termination. See this and the earlier examples we have discussed so far. To obtain termination, I propose to impose stronger conditions on improvement rules (see above). My guess is that thus we obtain termination. If we can guarantee termination, we know that Weak Coverage guarantees confluence. Hence, we can restore sound, complete and decidable type inference. > BTW, the above definition of the rank is still incomplete: it doesn't say > what rank(F t1 ... tm) is where F is an n-ary type constructor and > m < n. Hopefully, the rank of an incomplete type application is bounded > (otherwise, I have a non-termination example in mind). If the rank is > bounded, then the problem with defining an instance of MonadState > persists. For example, I may wish for a more complex state (which is > realistic): > > > newtype MyIOState a = MyIOState (Int -> IO (a,(Int,String,Bool))) > > instance MonadState (Int,String,Bool) MyIOState > > Now, the rank of the state is 4... > The simple solution might be for any n-ary type constructor F rank(F t1 ... tm) = 1 + rank t1 + ... + rank tm where m<=n This might be too naive, I don't know. I haven't thought about the case where we need to compute the rank of a type constructor. Though, the style of termination proof I'm using dates back to Prolog which we know is untyped. Hence, there might not be any problem after all? Martin