Resolving overlapping instances in external library

331 views Asked by At

I'm trying to show something of type Tagged s b (Data.Tagged) in a module that also imports from the accelerate library. Unfortunately, the accelerate library defines the show instance

instance Kit acc => Show (acc aenv a) where

in Data.Array.Accelerate.Pretty.hs. Reading around a bit, there's nothing I can do to avoid importing this instance, which obviously overlaps with the Data.Tagged Show instance. In fact, the generic accelerate instance prevents me from printing anything of kind *->*->*.

Here's a simple example that demonstrates the problem:

{-# LANGUAGE FlexibleContexts, OverlappingInstances, IncoherentInstances #-}

import Data.Array.Accelerate
import Data.Tagged

main :: (Show (Tagged Int Int)) => IO ()
main = let x = Tagged 3
   in print (x::Tagged Int Int)

The error:

    Overlapping instances for Show (Tagged * Int Int)
      arising from a use of `print'
    Matching instances:
      instance Show b => Show (Tagged k s b) -- Defined in `Data.Tagged'
      instance [overlap ok] accelerate-0.13.0.5:Data.Array.Accelerate.Trafo.Base.Kit
                          acc =>
                        Show (acc aenv a)
    -- Defined in `Data.Array.Accelerate.Pretty'

I have a few questions:

  1. I thought OverlappingInstances would allow me to resolve the instance, but I get the same error.
  2. IncoherentInstances should definitely let me compile...right? But it doesn't.
  3. Why does GHC report the Data.Tagged show instance as Show (Tagged k s b) when the instance (copied from Data.Tagged) is:

    instance Show b => Show (Tagged s b) where
    

I believe I have seen before where I was only able to resolve overlapping instances by adding an explicit type signature (to force GHC to choose the most specific instance), but as my example is at the top level and involves no polymorphism, I don't know how much more explicit I can be about the types.

My impression is that GHC should be able to choose the Data.Tagged instance since (I think) Tagged is not an instance of Accelerate.Base.Kit and therefore doesn't meet the instance constraints (I know we only match on the RHS of the instance, but GHC should be able to figure out that one of the instances couldn't possibly apply...)

EDIT

I created a bug report here, and the offending instance is now removed in the repo head. There's a great answer to #3 below, but I'm still interested in knowing why OverlappingInstances/IncoherentInstances didn't work.

1

There are 1 answers

0
Carl On BEST ANSWER

I only know the answer to 3.

When a type is compiled with -XPolyKinds and no restriction on the kind of a type variable, GHC prints the type very badly. After the type name, it prints a list of kinds of all the polymorphic type variables, then the type variables. So the k showing up in the type signature means that the type variable s can be of any kind. (Due to the way it's used, b must have kind *, so it's not kind-polymorphic, so its kind isn't listed.)

As an example of how ridiculous this can get, here's an example from the haddock docs of a library I'm working on now..

(SingI Nat a, SingI Nat b, SingI Nat c, SingI Nat d, SingI Nat e) => StaticSize ((,,,,) Nat Nat Nat Nat Nat) ((,,,,) Nat Nat Nat Nat Nat a b c d e)

It's using a promoted 5-tuple, too. That just makes it extra-silly, since that means the tuple shows up in both the kind and the type.