Haskell 如何让ReaderT使用另一个monad转换器?
我想将Haskell 如何让ReaderT使用另一个monad转换器?,haskell,monads,monad-transformers,Haskell,Monads,Monad Transformers,我想将ReaderT嵌入到另一个monad转换器中。我该怎么做?下面的示例使用了,但我认为它与任何其他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 imp
ReaderT
嵌入到另一个monad转换器中。我该怎么做?下面的示例使用了,但我认为它与任何其他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
您必须将作为
id
提供的参数更改为所有a的类型。m a->n a
和m Response->IO Response
。为什么?我不知道,但我发现的示例显示,有人运行与
main = do
let config = Config "Hello, world"
runner = flip runReaderT config
scottyT 3000 runner runner routes
我已经测试过了,至少它是有效的。我不知道这是否是最佳实践。如果有人有更好的方法,请随意发布。好吧,这是可行的,但我不确定它是否正确:
flip runReaderT config$scottyT 3000 id(flip runReaderT config)routes
。考虑到runReaderT
需要两次,我认为这是不正确的,但我对scotty了解不够,不知道为什么scottyT
函数需要参数,你能不能改变“转换堆栈”的顺序,即ReaderT配置(scottyT Text IO)(
?根据答案,你可以做'scottytt 3000'(flip runReaderT)(flip runReaderT)路由,其他人似乎就是这样做的。@chaosmatter不幸的是,没有。get
函数的类型是(ScottyError e,MonadIO m)=>RoutePattern->ActionT e m()->ScottyT e m()
,而不是更一般的(ScottyError e,MonadIO m,MonadAction a,MonadScotty s)=>RoutePattern->a e m()->s e m()
@chaosmatter我不想这么做。我想能够不用抬就可以使用Scotty
东西。如果有一个更容易理解的monad,它会是什么样子呢?看起来Scotty添加了一些魔法来实现这一点,但如果没有呢?这仍然是可能的吗?@seanclarkhes我通常看到的是,你会有类似Scotty的东西T::(ScottyError e,MonadIO m)=>端口->ScottyT e m()->m()
,那么您可以通过只运行scottyT
层来使用flip runReaderT config$scottyT 3000 routes
。scotty似乎需要一些更高级的行为来执行操作,我发现很难相信他们仅仅因为糟糕的API设计就需要这些复杂的额外参数。就我个人而言,我会这样做我更愿意先运行ReaderT
monad,留下scotty
monad作为我的基础,只运行scotty
,但这只是我对scotty的要求≥ 0.10,scottyT
不再将“Run monad'm'转换为monad'n”,在“scottyT'级别”参数处调用一次,因此最后一行应该是scottyT 3000 runner routes
。
main = do
let config = Config "Hello, world"
runner = flip runReaderT config
scottyT 3000 runner runner routes