<div dir="ltr"><div dir="ltr">> <span style="color:rgb(0,0,0);white-space:pre-wrap">A precondition is that it scans instances in </span><span style="color:rgb(0,0,0);white-space:pre-wrap">most-specific-first sequence</span><div><span style="color:rgb(0,0,0);white-space:pre-wrap">> -- which Hugs is already doing.</span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap"><br></span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap">It galled me that going only by (an adapted notion of) overlap, I still had to write three instances for a three-FunDep AddNat:</span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap"><br></span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap">> class AddNat x y z | x y -> z, x z -> y, y z -> x</span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap">></span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap">> instance</span>
<span style="color:rgb(0,0,0);white-space:pre-wrap"> </span><span style="color:rgb(0,0,0);white-space:pre-wrap">AddNat Z Z Z </span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap">> instance AddNat Z (S y') (S y')</span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap">></span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap">> instance AddNat x' y z' => AddNat (S x') y (S z')</span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap">></span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap"><br></span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap">because the 'obvious' way to write, with two instances (see below), put them in no substitution ordering for the argument positions to the third FunDep. So I dug out an idea from a few years ago (rejected proposal) and implemented:</span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap"><br></span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap">> </span><span style="color:rgb(0,0,0);white-space:pre-wrap">instance</span> <span style="color:rgb(0,0,0);white-space:pre-wrap"> </span><span style="color:rgb(0,0,0);white-space:pre-wrap">AddNat Z y y </span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap">></span></div><div><div><span style="color:rgb(0,0,0);white-space:pre-wrap">> instance AddNat x' y z' => AddNat (S x') y (S z') | y /~ (S z')</span></div>></div><div><br></div><div>That after the `|` in the instance is an 'Instance Disequality Guard': prefer a more specific instance if those two types from the head unify.</div><div><br></div><div>Then Hugs puts that instance later in the preference ordering than the first instance -- because the instance heads unify going by the argument positions, but the first instance has no guard.</div><div><br></div><div>This also works for the semi-overlap instances that Hugs currently rejects/GHC accepts but might turn out to be unusable:</div><div><br></div><div>> class Semi a b</div><div>></div><div>> instance Semi Int b</div><div>> instance Semi a Bool | a /~ Int</div><div>></div><div>> [W] Semi Int Bool -- GHC currently rejects as ambiguous</div><div><br></div><div>The guard says: in case of [W] Semi Int Bool, prefer the Semi Int b instance. We can even go:</div><div><br></div><div>> instance Semi Int Bool</div><div>></div><div>> instance Semi Int b | b /~ Bool</div><div>> instance Semi a Bool | a /~ Int</div><div>></div><div>> instance Semi a b -- no guard, because strictly more general than any instance</div><div><br></div><div><br></div></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
</blockquote></div></div>