
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