How to get ReaderT to work with another monad transformer?

匆匆过客 提交于 2019-12-29 08:06:53

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!