Haskell mtl,读卡器,不包括;堆叠顺序

Haskell mtl,读卡器,不包括;堆叠顺序,haskell,monad-transformers,Haskell,Monad Transformers,所以这会有点长,因为我不确定如何更笼统地阐述这个问题。好消息是,我在问题的底部有一个代码示例,这个想法只是为了让它构建起来&优雅:-) 我有两个函数,它们有如下签名: calledFunction :: (MonadReader env m, HasToken env, MonadIO m) => m (Either MyError MyResult) calledFunction2 :: (MonadReader env m, HasToken env, MonadIO m

所以这会有点长,因为我不确定如何更笼统地阐述这个问题。好消息是,我在问题的底部有一个代码示例,这个想法只是为了让它构建起来&优雅:-)

我有两个函数,它们有如下签名:

calledFunction
  :: (MonadReader env m, HasToken env, MonadIO m)
  => m (Either MyError MyResult)

calledFunction2
  :: (MonadReader env m, HasToken env, MonadIO m)
  => m (Either MyError MyResult2)
最后,我想得到一个类型为
的结果,除了字符串IO MyResult3
,它是通过组合
MyResult
MyResult2
得到的

现在非常好的是,
calledFunction
返回一个
,因为我可以利用:

ExceptT :: m (Either e a) -> ExceptT e m a
我只需键入调用的
EitherT函数
,我将不再有
m(或者MyError MyResult)
,而是直接的
除了MyError m MyResult)
。进步

但是我还需要为
调用的函数
提供它想要的读卡器上下文。现在,我将使用
runReaderT
来实现这一点。我现在来到了
除了MyError m MyResult
转换器堆栈之外的
,因此
ReaderT
应该放在
m
所在的位置。。所以
除了MyError(ReaderT Config IO)MyResult

除此之外,由于readerT位于转换器堆栈的底部,如何用要读取的值“填充”readerT?如果我反转堆栈以使读取器处于顶层,那么
运行readert
自然会出现,但我不知道如何使用
EitherT
ExceptT
优雅地转换我的

import Control.Monad.Reader
import Control.Monad.Trans.Reader
import Control.Monad.Trans.Except
import Control.Monad.IO.Class
import Control.Error -- 'error' package

class HasToken a where
    getToken :: a -> String
data Config = Config String
instance HasToken Config where
    getToken (Config x) = x

data MyError = MyError String deriving Show
data MyResult = MyResult String
data MyResult2 = MyResult2 String

data MyResult3 = MyResult3 MyResult MyResult2

calledFunction
  :: (MonadReader env m, HasToken env, MonadIO m)
  => m (Either MyError MyResult)
calledFunction = undefined

calledFunction2
  :: (MonadReader env m, HasToken env, MonadIO m)
  => m (Either MyError MyResult2)
calledFunction2 = undefined

cfg = Config "test"

main = undefined

test :: ExceptT MyError IO MyResult3
test = do
    -- calling runReaderT each time defeats the purpose..
    r1 <- ExceptT (runReaderT calledFunction cfg)
    r2 <- ExceptT (runReaderT calledFunction2 cfg)
    return $ MyResult3 r1 r2

test1 = runReaderT test2 cfg

test2 :: ReaderT Config (ExceptT MyError IO) MyResult3
test2 = do
    -- how to make this compile?
    let cfg = Config "test"
    r1 <- ExceptT calledFunction
    r2 <- ExceptT calledFunction2
    return $ MyResult3 r1 r2
import Control.Monad.Reader
导入控制.Monad.Trans.Reader
进口管制.单子交易.例外
导入控制.Monad.IO.Class
导入控件。错误--“错误”包
类HasToken a在哪里
getToken::a->String
数据配置=配置字符串
实例HasToken配置,其中
getToken(配置x)=x
数据MyError=MyError字符串派生显示
数据MyResult=MyResult字符串
数据MyResult2=MyResult2字符串
数据MyResult3=MyResult3 MyResult MyResult2
调用函数
:(莫纳德雷德环境m、哈斯托克环境m、莫纳迪奥环境m)
=>m(我的错误或结果)
calledFunction=未定义
调用函数2
:(莫纳德雷德环境m、哈斯托克环境m、莫纳迪奥环境m)
=>m(MyError或MyResult2中的任意一个)
calledFunction2=未定义
cfg=配置“测试”
main=未定义
测试::除MyError IO MyResult3外
测试=do
--每次调用runReaderT都会失败。。
r1您可以使用from来运行
除外
下的
读卡器

ghci> let foo = undefined :: ExceptT () (ReaderT () IO) ()
ghci> :t hoist (flip runReaderT ()) foo
hoist (flip runReaderT ()) foo :: ExceptT () IO ()
自己动手也很容易,只需使用
runExceptT
展开,为环境提供
runReader
,然后在
ExceptT
构造函数中重新包装结果:

ghci> :t \env -> ExceptT . flip runReaderT env . runExceptT
\env -> ExceptT . flip runReaderT env . runExceptT
    :: r -> ExceptT e (ReaderT r m) a -> ExceptT e m a
您可以使用from来运行
除外
下的
读取器

ghci> let foo = undefined :: ExceptT () (ReaderT () IO) ()
ghci> :t hoist (flip runReaderT ()) foo
hoist (flip runReaderT ()) foo :: ExceptT () IO ()
自己动手也很容易,只需使用
runExceptT
展开,为环境提供
runReader
,然后在
ExceptT
构造函数中重新包装结果:

ghci> :t \env -> ExceptT . flip runReaderT env . runExceptT
\env -> ExceptT . flip runReaderT env . runExceptT
    :: r -> ExceptT e (ReaderT r m) a -> ExceptT e m a

对,这样就可以了:
test=just(flip-runReaderT-cfg)$do…
。非常感谢。对,这样就可以了:
test=just(flip-runReaderT-cfg)$do…
。非常感谢。