relaxed instance rules spec (was: the MPTC Dilemma (please solve))

Simon Peyton-Jones simonpj at microsoft.com
Wed Mar 1 03:32:14 EST 2006


Claus,

I urge you to read our paper "Understanding functional dependencies via
Constraint Handling Rules", which you can find here
http://research.microsoft.com/%7Esimonpj/papers/fd%2Dchr/.

It will tell you more than you want to know about why relaxing
apparently-conservative rules is entirely non-trivial.   It's one of
those areas in which it is easy to suggest a plausible-sounding
alternative, but much harder to either prove or disprove whether the
alternative a sound one.

The paper describes rules we are reasonably sure of.   It would be great
to relax those rules.  But you do need to have a proof that the
relaxation preserves the properties we want.  Go right ahead!  The paper
provides a good framework for such work, I think.

Simon

| -----Original Message-----
| From: Claus Reinke [mailto:claus.reinke at talk21.com]
| Sent: 28 February 2006 19:54
| To: Simon Peyton-Jones; haskell-prime at haskell.org
| Subject: relaxed instance rules spec (was: the MPTC Dilemma (please
solve))
| 
| >The specification is here:
|
>http://www.haskell.org/ghc/dist/current/docs/users_guide/type-extension
s.html#instance-decls
| 
| two questions/suggestions about this:
| 
| 1. there are other termination criteria one migh think of, though
|     many will be out because they are not easy to specify. but here
|     is an annoyingly simple example that doesn't fit the current rules
|     even though it is clearly terminating (it's not even recursive):
| 
| class Fail all -- no instances!
| 
| class TypeNotEq a b
| instance Fail a => TypeNotEq a a
| instance TypeNotEq a b
| 
| class Test a b where test :: a -> b -> Bool
| instance TypeNotEq a b => Test a b where test _ _ = False
| instance Test a a where test _ _ = True
| 
| main = print $ (test True 'c', test True False)
| 
|     never mind the overlap, the point here is that we redirect from
|     Test a b to TypeNotEq a b, and ghc informs us that the
|     "Constraint is no smaller than the instance head".
| 
|     it is true that the parameters don't get smaller (same number,
|     same number of constructors, etc.), but they are passed to a
|     "smaller" predicate (in terms of call-graph reachability: there
|     are fewer predicates reachable from TypeNotEq than from
|     Test - in particular, Test is not reachable from TypeNotEq).
| 
|     this is a non-local criterion, but a fairly simple one. and it
seems
|     very strange to invoke "undecidable instances" for this example
|     (or is there anything undecidable about it?).
| 
| 2. the coverage condition only refers to the instance head. this
|     excludes programs such as good old record selection (which
|     should terminate because it recurses over finite types, and is
|     confluent -in fact deterministic- because of best-fit overlap
|     resolution):
| 
| -- | field selection
| infixl #?
| 
| class Select label val rec | label rec -> val where
|   (#?) :: rec -> label -> val
| 
| instance Select label val ((label,val),r) where
|   ((_,val),_) #? label = val
| 
| instance Select label val r => Select label val (l,r) where
|   (_,r)       #? label = r #? label
| 
|     now, it is true that in the second instance declaration, "val" is
|     not covered in {label,(l,r)}. however, it is covered in the
recursive
|     call, subject to the very same FD, if that recursive call complies
|     with the (recursive) coverage criterion. in fact, for this
particular
|     task, that is the only place where it could be covered.
| 
|     would it be terribly difficult to take such indirect coverage (via
|     the instance constraints) into account? there'd be no search
|     involved (the usual argument against looking at the constraints),
|     and it seems strange to exclude such straightforward "consume
|     a type" recursions, doesn't it?
| 
| cheers,
| claus



More information about the Haskell-prime mailing list