Вопрос

I have written a simple WAI application, which uses a ReaderT to allow access to the request like so:

import qualified Network.Wai as W
handle :: (Resource a) => a -> ReaderT W.Request IO W.Response

where handle is the function that does the bulk of the processing. I then call it in my application:

app :: W.Application
app = runReaderT (handle a) -- simplified; i don't think the value of a matters

main :: IO ()
main = run 3000 app

but runhaskell main.hs gives me the following:

Couldn't match expected type `Control.Monad.Trans.Resource.ResourceT
                                IO'
            with actual type `IO'
Expected type: ReaderT
                 W.Request (Control.Monad.Trans.Resource.ResourceT IO) W.Response
  Actual type: ServerMonad W.Response
In the return type of a call of `handle'
In the first argument of `runReaderT', namely
  `(handle a)'

which confuses me for two reasons:

  1. I don't have any idea why it's expecting that type
  2. Calling resp <- runReaderT (handle a) defaultRequest works in GHCI!

Why is this happening?

Это было полезно?

Решение

The type Application is defined as:

type Application = Request -> ResourceT IO Response

(The reason for ResourceT is so that you can allocate scarce resources and use them when sending a streaming response. This would be relevant for sending back a response based on a large database query. But that's not directly relevant for your question.)

Your runReaderT (reader a) has type Request -> IO Response. In order to get it to return the response in ResourceT IO, there seem to be two options:

  1. Lift it in app: app = lift . runReaderT (reader a). (lift is defined in Control.Monad.Trans.Class.)
  2. Change the type of hanlde to handle :: (Resource a) => a -> ReaderT W.Request (ResourceT IO) W.Response.

The first approach makes sense if you might ever need to perform a resource-sensitive operation, whereas the second will likely be an easier change.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top