5

This is a Haskell newb question probably to do with the IO() monad.

I've got a function in a Happstack.Server program that generates a response for a file upload.

postFile = do methodM POST
              decodeBody filePolicy
              (tmp, name, meta) <- lookFile "upload"
              ok $ concat ["A file! ", tmp, " || ", name, " || ", show meta]

That works fine. Now, I'd like it to display the content of the uploaded file as well as its local tempname, original name and content-type metadata. I was assuming that since this is all taking place in a do block, I could just

postFile = do methodM POST
              decodeBody filePolicy
              (tmp, name, meta) <- lookFile "upload"
              contents <- readFile tmp
              ok $ concat ["A file! ", tmp, " || ", name, " || ", show meta, "\n\n", contents]

but that hands me a string of errors that seems to tell me something is up with the decodeBody call.

...
/home/inaimathi/projects/happstack-tutorial/parameters.hs:23:15:
    No instance for (Happstack.Server.Internal.Monads.WebMonad
                       Response IO)
      arising from a use of `decodeBody'
    Possible fix:
      add an instance declaration for
      (Happstack.Server.Internal.Monads.WebMonad Response IO)
    In a stmt of a 'do' block: decodeBody filePolicy
    In the expression:
      do { methodM POST;
           decodeBody filePolicy;
           (tmp, name, meta) <- lookFile "upload";
           contents <- readFile tmp;
           .... }
    In an equation for `postFile':
        postFile
          = do { methodM POST;
                 decodeBody filePolicy;
                 (tmp, name, meta) <- lookFile "upload";
                 .... }
...

I'm not sure what's going wrong here. Can anyone educate me?


EDIT3:

That'll learn me to jump to conclusions.

The additional errors I was getting were all due to improperly installed libraries. Clearing out my ~/.ghc, then installing happstack again fixed it.

Inaimathi
  • 13,853
  • 9
  • 49
  • 93

1 Answers1

12
No instance for (Happstack.Server.Internal.Monads.WebMonad
                       Response IO)

Translation: your do-block is not the IO monad but some other monad. Fortunately, it turns out to be an instance of MonadIO:

class Monad m => MonadIO m where
    liftIO :: IO a -> m a

As you see, such an instance simply provides a way to 'lift' IO actions from the IO monad into itself, so in your case you just need:

contents <- liftIO $ readFile tmp

The implementation of liftIO obviously depends on m, but in a typical monad transformer stack it uses lift and liftIO to get to the IO monad inside; see e.g., the implementations for the other monad transformers in the Transformers library.

Fixnum
  • 1,842
  • 1
  • 13
  • 25
  • Added an edit to the question after trying this suggestion; it seems it's not quite as simple as adding `liftIO`. – Inaimathi Nov 02 '12 at 17:33
  • `Happstack.Server.Internal.Monads.ServerPartT IO String` (`:t` in `ghci` reports `Happstack.Server.Internal.Monads.ServerPartT IO [Char]`) – Inaimathi Nov 02 '12 at 21:02
  • I can't reproduce the `No instance for (Control.Monad.IO.Class.MonadIO (Happstack.Server.Internal.Monads.ServerPartT IO))` issue. Certainly the compiler should be able to deduce this instance from declarations in Happstack.Server.Internal.Monads and Control.Monad.IO.Class, so I'm confused. – Fixnum Nov 02 '12 at 22:17
  • A cosmetic suggestion -- the Internal modules aren't meant for use in applications, so you might consider giving `postFile` the type `ServerPart String` instead. – Fixnum Nov 02 '12 at 22:19
  • Added a type declaration of `postFile :: ServerPart String`, just to make it explicit. The version without `readFile` still works fine, but adding the additional assignment to `contents` gives me the same error. – Inaimathi Nov 02 '12 at 22:48
  • Out of curiosity, did you use any language pragmas when you tried to repro this? – Inaimathi Nov 03 '12 at 17:38
  • Hmm. Looks like the latest error is a result of my machine architecture (your suggestion works fine on a 32-bit machine, but still fails as I note above on 64-bit). – Inaimathi Nov 03 '12 at 19:49