I'm trying to get my MongoDB working in Haskell. I was using this tutorial as a starting point. When I do these commands in prelude, I get a list of collections:
pipe <- runIOE $ connect $ Host "XXXXX.mongolab.com" $ PortNumber 33317
access pipe master <databaseName> $ auth <username> <password>
access pipe master <databaseName> allCollections
However, when I try to put that in Yesod Handler, it's not compiling. I have
getActivityR :: Handler Import.Value
getActivityR = do
pipe <- runIOE $ connect $ Host "XXXXX.mongolab.com" $ PortNumber 33317
access pipe master <databaseName> $ auth <username> <password>
access pipe master <databaseName> allCollections
returnJson $ object ["activity" .= ("abc" :: Text)]
The returnJson is really just there to let me know I completed the method. Eventually it will return the list of activities.
The error I'm getting is:
Couldn't match type `IO' with `HandlerT App IO'
Expected type: HandlerT App IO Pipe
Actual type: IO Pipe
In a stmt of a 'do' block:
pipe <- runIOE
$ connect $ Host "XXXXXX.mongolab.com" $ PortNumber 33317
So what is the difference between Prelude/GHCi and my Yesod code being built by Cabal?
The problem is that GHCi runs your code in the IO
monad, while your function is in the HandlerT App IO
monad. But HandlerT
is a monad transformer over the IO
monad, so you can use lift
to "promote" your IO
action to a HandlerT App IO
action. The type of lift is:
lift :: (MonadTrans t, Monad m) => m a -> t m a
In your case, t
has to be HandlerT App
and m
has to be IO
.
So the correct code looks like this:
getActivityR :: Handler Import.Value
getActivityR = do
pipe <- lift $ runIOE $ connect $ Host "XXXXX.mongolab.com" $ PortNumber 33317
access pipe master <databaseName> $ auth <username> <password>
access pipe master <databaseName> allCollections
returnJson $ object ["activity" .= ("abc" :: Text)]
I don't know what your access
is, so I can't tell whether you need the lift there too or not.
For your special case, there is also liftIO
which is like lift
, but lifts straight to IO, not only to the next "layer" in your stack of monad transformers, so you should use it:
pipe <- liftIO $ runIOE $ connect $ Host "XXXXX.mongolab.com" $ PortNumber 33317
If you want to know more about this topic you should look for "monad transformers."