Take the 2-minute tour ×

I'm playing around with writing a web app. In this case, I'm using scotty and redis, but this problem comes up in any web/db combo. I used happstack before this, so I'd love an example there too.

Scotty has you define routes in a nested monad, which makes it easy to access the database connection within a route:

main = do
    db <- connect defaultConnectInfo
    scotty 3000 $ do

    get "/keys" $ do
        keys <- liftIO $ runRedis db $ keys "*"
        html $ T.pack $ show keys

The do block in get has type: Web.Scotty.ActionM (). All the redis commands have type Database.Redis.Redis a. Neither redis or scotty has a monad transformer.

What's the best way to combine these? I'm new to haskell, but I did manage to get ReaderT working with the web monad in happstack.

Ideally, I could somehow make a new monad stack that supports both keys and html in the same do block.

share|improve this question
Do people normally just settle for liftIO in haskell web frameworks? –  Sean Clark Hess Jan 27 '12 at 14:30
I don't know an answer here, but I figure your problem is similar to monad transformers. Basically, you want to implement a type, let's call it IdentityTT m' m a, such that IdentityTT m' behaves exactly like IdentityT. The first question to be answered, of course, is if that's even possible. –  Luis Casillas Jan 27 '12 at 18:57
Another way to phrase the question is: Do you use liftIO to query a database in all haskell frameworks? What the most common pattern when the database isn't baked into the framework? –  Sean Clark Hess Jan 28 '12 at 0:49
I don't see the problem with liftIO here? –  sclv Jan 29 '12 at 22:00
add comment

1 Answer

up vote 2 down vote accepted

For some reason I felt like liftIO was ugly, but it's really not bad. Especially if you do this:

queryRedis :: Connection -> Redis a -> ActionM a
queryRedis db r = liftIO $ runRedis db r

And define a partially applied function redis = queryRedis db. Thanks everyone

share|improve this answer
add comment

Your Answer


