[Haskell-beginners] Haskell wants the type, but I only know the class.

Amy de Buitléir amy at nualeargais.ie
Thu Nov 3 17:55:32 CET 2011


I'm trying to read something from a file, do something with it, and then write
it out again. I don't know, or care about, the type of the object I'm reading,
but I do know its class. Here's my code:

----------
import Data.Binary ( Binary, encode, decode )
import Data.ByteString.Lazy as B ( readFile, writeFile )
import Codec.Compression.GZip ( compress, decompress )

class ( Binary a, Show a, Eq a ) => Thing a where
  doSomething :: a -> IO a

readThing :: ( Thing a ) => FilePath -> IO a
readThing f =
    return . decode . decompress =<< B.readFile f

writeThing :: ( Thing a ) => FilePath -> a -> IO ()
writeThing f = B.writeFile f . compress . encode

main = do
  a <- readThing "file1.txt"
  a' <- doSomething a
  writeThing "file2.txt" a'
----------

And here's the compiler error I get. 

Amy.hs:18:3:
    Ambiguous type variable `a0' in the constraint:
      (Thing a0) arising from a use of `writeThing'
    Probable fix: add a type signature that fixes these type variable(s)
    In the expression: writeThing "file2.txt" a'
    In the expression:
      do { a <- readThing "file1.txt";
           a' <- doSomething a;
           writeThing "file2.txt" a' }
    In an equation for `main':
        main
          = do { a <- readThing "file1.txt";
                 a' <- doSomething a;
                 writeThing "file2.txt" a' }

Is there a way to fix my code? I tried adding a type signature, e.g.,

  a <- readThing "file1.txt" :: (Thing t) => IO t
  a' <- doSomething a :: (Thing t) => IO t

but then it says...

    Couldn't match type `t0' with `t'
      because type variable `t' would escape its scope
    This (rigid, skolem) type variable is bound by
      an expression type signature: Thing t => IO t
    The following variables have types that mention t0
      a :: t0 (bound at Amy.hs:16:3)
    In a stmt of a 'do' expression:
        a' <- doSomething a :: Thing t => IO t
    In the expression:
      do { a <- readThing "file1.txt" :: Thing t => IO t;
           a' <- doSomething a :: Thing t => IO t;
           writeThing "file2.txt" a' }
    In an equation for `main':
        main
          = do { a <- readThing "file1.txt" :: Thing t => IO t;
                 a' <- doSomething a :: Thing t => IO t;
                 writeThing "file2.txt" a' }




More information about the Beginners mailing list