Monday, May 21, 2012

GHC Talks to the Scarecrow

I have a strange sense of humor. It's essential that you know that before reading on.  'Cause really, this is a pretty dry little post about an obscure error in a Haskell program.

Today, I got a message from GHC that always amuses me. Why?  Because the message makes feel like GHC is poor little Dorothy, stuck at the fork in the road, confused by the Scarecrow's advice that some people go both ways.

Here's a simplified version of the program:

{-# LANGUAGE FlexibleInstances, OverloadedStrings #-}
import qualified Data.Text as T
class Argh a where
    toArgh :: a -> Char
instance Argh T.Text where
    toArgh = T.head
instance Argh [Char] where
    toArgh = head
x :: Char
x = toArgh "Argh!"
In response, GHC complains:

    Ambiguous type variable `a0' in the constraints:
      (Data.String.IsString a0)
        arising from the literal `"Argh!"' at Argh.hs:14:12-18
      (Argh a0) arising from a use of `toArgh' at Argh.hs:14:5-10
    Probable fix: add a type signature that fixes these type variable(s)
    In the first argument of `toArgh', namely `"Argh!"'
    In the expression: toArgh "Argh!"
    In an equation for `x': x = toArgh "Argh!"
Failed, modules loaded: none.
Funny, no?  It's amusing to me because the directive OverloadedStrings is designed to make it easy on the programmer in the time of  many string types, letting you use the quoted string to produce either [Char] or Text, depending on the context.  But in this case, both contexts occur in the same place, since the class Argh has instances for both types.

Now, if GHC were psychic, it could see that all roads lead to Rome.  Or the Emerald City.  Or something like that. The result is the same, either path it chooses.  But I'm just as happy that it doesn't choose for me. I'm just as happy to either remove the OverloadedStrings directive or put in a an explicit type declaration and move on.  After a little chuckle thinking about the Scarecrow.



Edward Kmett said...

Add the pragma:

{-# LANGUAGE ExtendedDefaultRules #-}

and then

default (T.Text)

will fix your problem. If you want to use OverloadedStrings, you'll need ExtendedDefaultRules to stay sane. ;)

Clifford Beshers said...

Bonus! Thank you Edward Kmett, I had missed the existence of ExtendedDefaultRules entirely.

GHC still isn't psychic, just really, really useful.