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…
。非常感谢。