问题
I would like to embed ReaderT
into another monad transformer. How do I do this? The example below uses Scotty but I think it would be the same with any other monad.
{-# LANGUAGE OverloadedStrings #-}
import qualified Web.Scotty
import Web.Scotty.Trans
import Data.Text.Lazy
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Reader
import Control.Monad.Trans
data Config = Config Text
main :: IO ()
main = do
let config = Config "Hello World"
-- how to I make this line work?
scottyT 3000 id id routes
routes :: ScottyT Text (ReaderT Config IO) ()
routes = do
get "/" info
info :: ActionT Text (ReaderT Config IO) ()
info = do
-- this part seems like it works!
Config message <- lift ask
text $ "Info: " `append` message
This errors on the line scottyT 3000 id id routes
, because scottyT
expects a ScottyT Text IO ()
. How do I make this work? Here are the current errors:
Server.hs: line 24, column 24:
Couldn't match type `ReaderT Config IO' with `IO'
Expected type: ScottyT Text IO ()
Actual type: ScottyT Text (ReaderT Config IO) ()
回答1:
You have to change the arguments you've supplied as id
to be ones that have the type forall a. m a -> n a
and m Response -> IO Response
respectively. Why? I don't know, but the example I found here shows someone running it similar to
main = do
let config = Config "Hello, world"
runner = flip runReaderT config
scottyT 3000 runner runner routes
I've tested it, and it at least works. Whether or not this is best practices is unknown to me. If someone has a better method, feel free to post it.
来源:https://stackoverflow.com/questions/26065765/how-to-get-readert-to-work-with-another-monad-transformer