<div dir="ltr">The HList project (~2004) had to abandon Hugs because (for example) they couldn't express a type-level type equality test.<div><br></div><div>Hugs rejects any attempt 'Instances are not consistent with Functional Dependencies'. Here's the equivalent that works in GHC.</div><div><br></div><div>>    class TypeEq a b e  | a b -> e</div><div>>    instance                                      TypeEq a a TTrue</div><div>>    instance {#- OVERLAPPABLE -#} (e ~ TFalse) => TypeEq a b e</div><div><br></div><div>Hugs rejects the equivalent of these instances because it can unify the instance heads' determining positions (as TypeEq a a e0) but the improvement diverges. Hugs always treats a wildcard e0 as apart from any specific type or from any other wildcard; whereas GHC treats them as unifiable, so accepts the instances. The instances (whole heads) are overlappable, so GHC's overlapping instances mechanism will improve e ~ TFalse only on condition it can't unify types a, b at some usage site.</div><div><br></div><div>SPJ points out <a href="https://gitlab.haskell.org/ghc/ghc/-/wikis/Functional-dependencies-in-GHC/Key-examples/FunDep-improvement-vs-instance-selection#qs-for-spj">https://gitlab.haskell.org/ghc/ghc/-/wikis/Functional-dependencies-in-GHC/Key-examples/FunDep-improvement-vs-instance-selection#qs-for-spj</a> that using an instance head to improve under a FunDep is a separate step and proceeds first vs selecting an instance. So this form for the second instance won't work in GHC:</div><div><br></div><div>>    instance                            TypeEq a b TFalse</div><div><br></div><div>(Also the instance heads are not overlapping.) In case of TypeEq a a e0, instance improvement will find both instances match and improve e0 ~ TTrue, e0 ~ TFalse, then reject as inconsistent, same as Hugs.</div><div><br></div><div>But notice this FunDep is 'Full' -- that is, mentions all of the classes, parameters. ('Full' FunDep is introduced in the 2008 'via CHRs' paper.)</div><div><br></div><div>If improvement can use a Full FunDep matching to an instance head, it has in effect selected that instance. This is really using the instance as a _candidate_ for improvement -- it might be the Dependent types are already improved as far as possible before looking at this instance. (That is, if we already have [W] TypeEq Int Int TTrue, looking to the instance heads won't improve further; but Hugs is not smart enough to shortcut that TTrue can't be improved.)</div><div><br></div><div>Hugs' type routines at this step of compilation are very much focussed on improving types, not selecting instances. And in case of a class with multiple FunDeps, the routines should 'fire' all possible FunDeps for each instance.</div><div><br></div><div>However it's only a small mod in routine instImprove to say: upon matching to a Full FunDep for an instance, stop looking at other instances for improvement. A precondition is that it scans instances in most-specific-first sequence -- which Hugs is already doing. So I can write these instances</div><div><br></div><div>> class     TypeEq a b e  | a b -> e</div><div>> instance TypeEq a a TTrue</div><div>> instance TypeEq a b TFalse</div><div><br></div><div>Without needing to clutter the instances by deferring improvement to constraints. (This also makes type inference error messages less cluttered.)</div><div><br></div><div>I'm now working on the instance sequencing routines, to ignore those divergent Dependent positions when deciding overlap ordering.</div><div><br></div><div>AntC</div></div>