[GHC] #15632: Undependable Dependencies

GHC ghc-devs at haskell.org
Wed Oct 10 03:06:43 UTC 2018


#15632: Undependable Dependencies
-------------------------------------+-------------------------------------
        Reporter:  AntC              |                Owner:  (none)
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:  8.6.1
       Component:  Compiler          |              Version:  8.6.1-beta1
      Resolution:                    |             Keywords:
                                     |  FunctionalDependencies,
                                     |  OverlappingInstances
Operating System:  Unknown/Multiple  |         Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:  10675, 9210,      |  Differential Rev(s):
  8634                               |
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by AntC):

 There is a structure of instances for which the suggested rules at
 comment:2 are over-restrictive: you can code round it under the rules, but
 awkwardly. I'd appreciate feedback on how common this is: a diamond
 overlap pattern. Consider

 {{{#!hs
 class Whuther a b  | a -> b  where ...

 instance Whuther (Int, a2, Bool) Hither  where ...

 instance (b ~ Thither) => Whuther (Int, a2, a3) b  where ...

 instance (b ~ Thither) => Whuther (a1, a2, Bool) b  where ...

 instance (b ~ Yon) Whuther (a1, a2, a3) b  where ...

 }}}

 The `Hither`instance is strictly more specific than any of the other
 three; the `Yon` instance is strictly more general. The two `Thither`
 instances overlap, but are in no substitution order, so don't meet
 conditions B ii), B iii) above. (For the example, it's not necessary the
 two instances produce the same result type for `b`, it just makes the
 example more poignant. Also it's not necessary for there to be a more
 general instance; in practice there usually is a 'catch-all'.)

 Currently GHC accepts this example, and does the 'right thing'. (Saying
 GHC accepts it is not much of a claim: GHC will accept nearly any rubbishy
 set of instances; whether it does the 'right thing' in all cases needs a
 lot of testing.)

 The example can be coded within the rules, via an auxiliary class:

 {{{#!hs
 class Whuther a b  | a -> b  where ...

 instance Whuther (Int, a2, Bool) Hither  where ...

 instance (b ~ Thither) => Whuther (Int, a2, a3) b  where ...

 instance (Whuther2 (a1, a2, a3) b) => Whuther (a1, a2, a3) b  where ...

 class Whuther2 a b  | a -> b  where ...

 instance (b ~ Thither) => Whuther2 (a1, a2, Bool) b  where ...

 instance (b ~ Yon) Whuther2 (a1, a2, a3) b  where ...

 }}}
 This has taken a symmetric set of instances to asymmetric, arbitrarily
 moving one of the instances into the auxiliary class.

 A very similar set of instances that GHC also accepts, but for which it's
 not clear what would be the 'right thing':

 {{{#!hs
 class Whuther a b  | a -> b  where ...

 instance Whuther (Int, Char, Bool) Hither  where ...

 instance (b ~ Thither) => Whuther (Int, a2, a3) b  where ...

 instance (b ~ Thither) => Whuther (a1, a2, Bool) b  where ...

 instance (b ~ Yon) Whuther (a1, a2, a3) b  where ...

 }}}

 These are accepted because of GHC's delayed/relaxed overlap check. then
 consider a wanted `Whuther (Int, a2, Bool) b` in which `a2` is known to be
 apart from `Char`. This gives irresolvable overlap, because there's no
 reason to prefer either of the `Thither` instances.

 I could amend the rules, still keeping within the idea of pairwise
 validation of instance heads. If A), B) fail:

 C) Relax to follow GHC's bogus consistency check providing all of

     i) The FunDep is full;

     ii) The instances overlap but neither is strictly more specific;
         there is a third instance strictly more specific than either; and

     iii) that third instance's argument positions taken together are
 exactly at the unification of the two partially-overlapping instances'
 argument positions.

         (i.e. the third instance's result positions are not less specific
 than the unification.)

 C ii), iii) together need search amongst instances. Note there could be at
 most one instance that would meet the criteria:

 * `Whuther (Int, a2, Bool) Hither` meets C ii), its `(Int, a2, Bool)`
 exactly meets C iii).

 * `Whuther (Int, Char, Bool) Hither` meets C ii), but its `(Int Char,
 Bool)` is too specific for C iii).

 * Note that both of those instances could legitimately be in scope under
 the rules: they're in a strict substitution order; and their FunDep result
 position is the same (meets condition A)'s strict consistency condition).

 To make the search a bit more deterministic, we could revise C ii) to
 require

 C)    ii') Neither of the instances is strictly more specific; and
         there is a third instance at exactly the unification of the two
 instances.

 Then C iii) is not needed. Under C ii'), the example at the top of this
 comment would be rejected, but the `Hither` instance could be amended to:

 {{{#!hs

 instance (b ~ Hither) => Whuther (Int, a2, Bool) b  where ...
 }}}

 And that would still allow another `instance Whuther (Int, Char, Bool)
 Hither`, which is strictly more specific yet.

 I've tried coding either version of rule C). It needs **either** entirely
 restructuring the consistency check to delay until all the instances are
 visible (rather than validating instances one-by-one in order of textual
 appearance); **or** requiring the programmer write the overlapping
 instances in textual order most-specific first. Usual practice is to write
 most-specific first. Never the less this makes the validation rules
 brittle: programmers won't appreciate error messages suggesting re-
 ordering their instances ''might'' help (no guarantee).

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15632#comment:5>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list