
Hello! I've been having a tough time trying to use the CGI monad transformer (CGIT). Hopefully someone can show me my misstep(s). I have a CGI script that's evolving. Early on, it needed a single database access. Now it's doing two accesses (and it looks like I'll be adding more.) Rather than making a connection for each access, the script needs to connect once. To do this, I want to combine the CGI monad with the Reader monad. This version compiles cleanly:
module AppMonad (App (..), runApp) where
import Control.Exception (bracket) import Control.Monad.Reader import Network.CGI.Monad import Network.CGI.Protocol import System.IO (stdin, stdout) import Database.HSQL.PostgreSQL
newtype App a = App (ReaderT Connection (CGIT IO) a) deriving (Monad, MonadIO, MonadReader Connection)
runApp :: App CGIResult -> IO () runApp (App a) = bracket (connect "host" "dbname" "user" "password") disconnect (\c -> do { env <- getCGIVars ; hRunCGI env stdin stdout (runCGIT (runReaderT a c)) ; return () } )
Unfortunately, when another module tries to actually use the monad, I get warnings about "No instance for (MonadCGI App)". I tried making an instance:
instance MonadCGI App where cgiAddHeader = ? cgiGet = ?
But I don't know how to define these functions. I tried various 'lift'ing combinations, but couldn't come up with a solution that would compile. I'm also disappointed that I had to break apart 'runCGI' (by cut-and-pasting its source) because I couldn't make it believe my monad looked enough like MonadCGI. My previous experiment with monad transformers was successful. It didn't use CGIT, however, so the 'run*' functions were simpler. Does anyone have an example of using CGIT (I didn't find any from Google)? Shouldn't I be able to use 'runCGI' with my monad? CGIT users shouldn't be required to re-implement 'runCGI", right? Any help or ideas is appreciated! -- Rich JID: rich@neswold.homeunix.net AIM: rnezzy

On Wed, Aug 22, 2007 at 01:27:00PM -0500, Rich Neswold wrote:
newtype App a = App (ReaderT Connection (CGIT IO) a) deriving (Monad, MonadIO, MonadReader Connection)
Unfortunately, when another module tries to actually use the monad, I get warnings about "No instance for (MonadCGI App)". I tried making an instance:
instance MonadCGI App where cgiAddHeader = ? cgiGet = ?
You have three choices: 1: Install the unportable (works in GHC, not sure about hugs, not in anything else TTBOMK) cgi-undecidable package and import Network.CGI.Undecidable. instance MonadCGI App where cgiAddHeader n v = App $ cgiAddHeader n v cgiGet x = App $ cgiGet x Here Network.CGI.Undecidable provides the instance for MonadReader. The nice thing about this one is it'll keep working is you later add a StateT, say. 2: Provide an instance for ReaderT and an instance for App that uses it: instance MonadCGI App where cgiAddHeader n v = App $ cgiAddHeader n v cgiGet x = App $ cgiGet x instance MonadCGI m => MonadCGI (ReaderT c m) where cgiAddHeader n v = lift $ cgiAddHeader n v cgiGet x = lift $ cgiGet x Here the individual bits will keep working if you add a StateT, but you will also need to add a StateT instance. 3: Provide a single instance for App that does the whole thing: instance MonadCGI App where cgiAddHeader n v = App $ lift $ cgiAddHeader n v cgiGet x = App $ lift $ cgiGet x This one you would obviously have to change if you added a StateT.
I'm also disappointed that I had to break apart 'runCGI' (by cut-and-pasting its source) because I couldn't make it believe my monad looked enough like MonadCGI.
runApp :: App CGIResult -> IO () runApp (App a) = bracket (connect "host" "dbname" "user" "password") disconnect (\c -> runCGI (runReaderT a c)) (the above is mostly untested, so it may be wrong in some details). Thanks Ian

On 8/22/07, Ian Lynagh
On Wed, Aug 22, 2007 at 01:27:00PM -0500, Rich Neswold wrote:
newtype App a = App (ReaderT Connection (CGIT IO) a) deriving (Monad, MonadIO, MonadReader Connection)
Unfortunately, when another module tries to actually use the monad, I get warnings about "No instance for (MonadCGI App)". I tried making an instance:
instance MonadCGI App where cgiAddHeader = ? cgiGet = ?
You have three choices:
1:
2:
3: Provide a single instance for App that does the whole thing: instance MonadCGI App where cgiAddHeader n v = App $ lift $ cgiAddHeader n v cgiGet x = App $ lift $ cgiGet x This one you would obviously have to change if you added a StateT.
Bingo! Method #3 works beautifully! I missed the using-lift-with-the-constructor permutation. Thanks for your help! -- Rich JID: rich@neswold.homeunix.net AIM: rnezzy

On Aug 23, 2007, at 3:34 , Rich Neswold wrote:
On 8/22/07, Ian Lynagh
wrote: On Wed, Aug 22, 2007 at 01:27:00PM -0500, Rich Neswold wrote: newtype App a = App (ReaderT Connection (CGIT IO) a) deriving (Monad, MonadIO, MonadReader Connection)
Unfortunately, when another module tries to actually use the
monad, I
get warnings about "No instance for (MonadCGI App)". I tried making an instance:
instance MonadCGI App where cgiAddHeader = ? cgiGet = ?
You have three choices:
1:
2:
3: Provide a single instance for App that does the whole thing: instance MonadCGI App where cgiAddHeader n v = App $ lift $ cgiAddHeader n v cgiGet x = App $ lift $ cgiGet x This one you would obviously have to change if you added a StateT.
Bingo! Method #3 works beautifully! I missed the using-lift-with- the-constructor permutation.
Thanks for your help!
I started writing a tutorial for Haskell web programming with the cgi package a while back, but haven't worked on it for a while, see http://www.haskell.org/haskellwiki/Practical_web_programming_in_Haskell I haven't added it to the list of tutorials yet, since it's still rather incomplete. The section on using CGIT is just a stub, perhaps you would like to contribute to it? See http://www.haskell.org/haskellwiki/ Practical_web_programming_in_Haskell#Extending_the_CGI_monad_with_monad_ transformers /Björn

On 8/24/07, Bjorn Bringert
On Aug 23, 2007, at 3:34 , Rich Neswold wrote:
Bingo! Method #3 works beautifully! I missed the using-lift-with- the-constructor permutation.
Thanks for your help!
I started writing a tutorial for Haskell web programming with the cgi package a while back, but haven't worked on it for a while, see http://www.haskell.org/haskellwiki/Practical_web_programming_in_Haskell I haven't added it to the list of tutorials yet, since it's still rather incomplete.
The section on using CGIT is just a stub, perhaps you would like to contribute to it? See http://www.haskell.org/haskellwiki/ Practical_web_programming_in_Haskell#Extending_the_CGI_monad_with_monad_ transformers
Done. As I learn more about using CGIT, I'll try to remember to add more content. Any suggestions to improve it are welcome! -- Rich JID: rich@neswold.homeunix.net AIM: rnezzy
participants (3)
-
Bjorn Bringert
-
Ian Lynagh
-
Rich Neswold