首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >mapMonadTrans ::MonadTrans xT => (m a -> n b) -> xT m a -> xT n b

mapMonadTrans ::MonadTrans xT => (m a -> n b) -> xT m a -> xT n b
EN

Stack Overflow用户
提问于 2011-07-07 02:27:41
回答 4查看 285关注 0票数 5

问题是这样的。我有:

代码语言:javascript
复制
f :: MonadIO m => ReaderT FooBar m Answer;
f = (liftIO getArgs) >>= ...

我需要用修改过的参数来运行它。但是,由于m是未知的,所以我不能简单地使用

代码语言:javascript
复制
mapReaderT (withArgs args) :: ReaderT r IO b -> ReaderT r IO b

因为我需要以某种方式将(withArgs args)转换为所有m的m。

我发现的一种可能性是定义自己的withArgs,如下所示:

代码语言:javascript
复制
import System.Environment (setArgs, freeArgv);
withArgv new_args act = do {
  pName <- liftIO System.Environment.getProgName;
  existing_args <- liftIO System.Environment.getArgs;
  bracket (liftIO $ setArgs new_args)
          (\argv -> do {
                      _ <- liftIO $ setArgs (pName:existing_args);
                      liftIO $ freeArgv argv;
                    })
          (const act);
};

withArgs xs act = do {
  p <- liftIO System.Environment.getProgName;
  withArgv (p:xs) act;
};

然而,这是一个杂乱无章的东西,而且是特定于一个函数的--我需要重写每个withX :: X -> IO a -> IO a,例如Control.Exception.handle

如果有的话,有什么更好的方法来做到这一点?

编辑:在handle的情况下,我找到了Control.Monad.CatchIO。在另一种情况下,我使用了另一个更简短的杂凑(不值得张贴)来避免上面的杂凑。还在寻找更好的解决方案!

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-07-07 04:33:50

monad-control包可以做到这一点。我认为您需要来自Control.Monad.IO.Control的函数liftIOOp_

具体来说,

代码语言:javascript
复制
liftIOOp_ (withArgs newArgs) f

应该做你想做的事。您也可以使用liftIOOp函数来提升诸如bracket之类的东西。

票数 4
EN

Stack Overflow用户

发布于 2011-07-07 05:03:19

您正在寻找的部分内容是将monad同态提升到monad transformer中。

代码语言:javascript
复制
class MonadHoist t where
    hoist :: (Monad m, Monad n) => (forall a. m a -> n a) -> t m a -> t n a

    t :: Monad m => t Identity a -> t m a
    t = hoist (return . runIdentity)

也就是说,给定一个从mn的单同态f,您可以使用hoist得到一个从t mt n的单同态。

monad同态比上述类型的强制略强,即它负责保持monad定律。

代码语言:javascript
复制
f . return = return
f . fmap g = fmap g . f
f . join = join . f . fmap f
         = join . fmap f . f -- by the second law
         = (>>= f) . f       -- >>= in terms of join

请注意我在hoist类型中偷偷添加的量词,MonadHoist几乎对所有实例都需要这种灵活性!(Reader恰好是唯一一种不需要这种灵活性的情况,试着在没有它的情况下编写MaybeT )。

一般来说,Monad转换器可以实例化这个类。例如:

代码语言:javascript
复制
instance MonadHoist (StateT s) where
    hoist f (StateT m) = StateT (f . m)

instance MonadHoist (ReaderT e) where
    hoist f (ReaderT m) = ReaderT (f . m)

instance MonadHoist MaybeT where
    hoist f (MaybeT m) = MaybeT (f m)

我们目前没有在transformersmtl包中提供它,因为它需要一个Rank2Type,但它的实现非常简单。

如果有足够的需求,我将很乐意将其打包成monad-extras包。

现在,我说的是部分,因为虽然这回答了你帖子主题中的类型给出的问题,但它没有解决与你的问题相关的大部分文本所反映的需求!

为此,您可能希望遵循luqui的建议。=)

票数 9
EN

Stack Overflow用户

发布于 2011-07-07 03:01:09

我相信interleavableIO package解决了这个问题。在this cafe thread中对此进行了讨论。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6601208

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档