4
votes

I have the following Haskell code using overlapping instances; I tried to implement a function which yield the funcion's type as a String, or -- more generally speaking -- does different things for different function types:

{-# OPTIONS_GHC -fglasgow-exts #-}
{-# LANGUAGE OverlappingInstances, IncoherentInstances #-}

module Test
where

data TypeString = MKTS String 

instance Show TypeString where
  show (MKTS s) = s

class ShowType b c where
  theType :: (b -> c) -> TypeString

instance ShowType b b where
  theType _ = MKTS "b -> b" 

instance ShowType b c where
  theType _ = MKTS "b -> c" 

instance ShowType (b, b') c where
  theType _ = MKTS "(b, b') -> c"

class Problem a where
  showProblem :: a -> TypeString

instance Problem (b -> c) where
  showProblem f = theType f

Haskell shows the expected behavior when I type

> theType (uncurry (+))
(b,b') -> c

But: Can anyone explain the following:

> showProblem (uncurry (+))
b -> c

... and explain, how to avoid such situations where Haskell chooses a too general instance...

1

1 Answers

2
votes

The instance for Problem used is made for b -> c. If you look at the signature of showProblem, you will see that there is no ShowType context. If there is no context, the compiler can only infer the instance statically. Because of this, the instance for b -> c is chosen, as it is the instance that fits statically.

I don't know how to solve this, IMHO it could work to provide the context by hand, but I really don't know:

class Problem a where
  showProblem :: ShowType a => a -> TypeString

instance Problem (b -> c) where
  showProblem :: ShoType (b -> c) => (b -> c) -> TypeString
  showProblem = theType

For me, using OverlappingInstances usually means, that I did a wrong design decision in my code.