Happstack display a read file
Asked Answered
F

1

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.

Falcon answered 2/11, 2012 at 3:23 Comment(2)
Don't know Happstack, but you probably need to use liftIO $ readFile tmp.`Platt
As others have said, you just need 'liftIO'. I will add a section to the Crash Course on this.Foliolate
I
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.

Iaverne answered 2/11, 2012 at 5:1 Comment(7)
Added an edit to the question after trying this suggestion; it seems it's not quite as simple as adding liftIO.Falcon
Happstack.Server.Internal.Monads.ServerPartT IO String (:t in ghci reports Happstack.Server.Internal.Monads.ServerPartT IO [Char])Falcon
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.Iaverne
A cosmetic suggestion -- the Internal modules aren't meant for use in applications, so you might consider giving postFile the type ServerPart String instead.Iaverne
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.Falcon
Out of curiosity, did you use any language pragmas when you tried to repro this?Falcon
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).Falcon

© 2022 - 2024 — McMap. All rights reserved.