[Haskell-cafe] Stupid question, re: overloaded type classes

Ryan Ingram ryani.spam at gmail.com
Sun Jan 18 15:44:02 EST 2009


On Sun, Jan 18, 2009 at 11:23 AM, Brian Hurt <bhurt at spnz.org> wrote:
> instance Sexpable String where

> instance Sexpable a => Sexpable [ a ] where

> Note that I am not implementing Sexpable Char anywhere, so the only valid
> transform for [Char] should be the String one.  But this still causes a
> compiler error due to the overloaded instances on [Char].

> So my question is twofold: 1) what errors might be allowed if I add
> -fallow-incoherent-instances, and 2) is there some third choice that avoids
> both solutions I already know about?

1) Incoherent instances end up being used in code like this:

blah :: Sexpable a => a -> Sexp
blah x = toSexp [x]

In this case, assuming an instance for Sexpable Char, this code may or
may not use the "wrong" instance, depending on what happens with
inlining:

blah 'x'

which passes the dictionary for Sexpable Char and then probably uses
the instance Sexpable a => Sexpable [a] (with a = Char), instead of
Sexpable String.

As long as there are no instances for Sexpable Char anywhere,
incoherent instances won't cause an error in this case.  That said,
you can't guarantee that someone won't go and add an instance for
Char.

2) A third choice is to do what Show does, which is kind of a hack but
solves this specific problem:

class Sexpable a where
    toSexp :: a -> Sexp
    fromSexp :: Sexp -> Maybe a

    toSexpList :: [a] -> Sexp
    fromSexpList :: Sexp -> Maybe [a]

    toSexpList = List . map toSexp
    fromSexpList (List lst) = mapM fromSexp lst
    fromSexpList _ = Nothing

instance Sexpable a => Sexpable [a] where
    toSexp = toSexpList  -- from Sexpable a, not [a]
    fromSexp = fromSexpList

This requires Sexpable Char, though, to give you the right place to
put the instance.  But it seems easy enough to include those; is there
a reason you explicitly don't want an instance for Char?

instance Sexpable Char where
   toSexp c = toSexpList [c]
   fromSexp l = do
       [c] <- fromSexp l
       return c
   toSexpList s = Atom s
   fromSexpList (Atom s) = Just s
   fromSexpList _ = Nothing

I think that a design for typeclasses that eliminates the need for the
"showList" hack would be quite welcome.

  -- ryan


More information about the Haskell-Cafe mailing list