mapMonadTrans :: MonadTrans xT => (ma→nb)→ xTma-> xTnb

发布于 2024-11-18 22:00:18 字数 1127 浏览 7 评论 0原文

问题是这样的。我有:

f :: MonadIO m => ReaderT FooBar m Answer;
f = (liftIO getArgs) >>= ...

我需要使用修改后的参数来运行它。然而,由于 m 未知,我不能简单地使用,

mapReaderT (withArgs args) :: ReaderT r IO b -> ReaderT r IO b

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

我发现的一种可能性是定义我自己的 withArgs,因此:

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一-> IO a,例如 Control.Exception.handle

什么(如果有)更好的方法可以做到这一点?

编辑:在句柄的情况下,我找到了 Control.Monad.CatchIO。在另一种情况下,我使用了另一个更简短的组装(不值得发布)来避免上面的组装。仍在寻求更好的解决方案!

The problem is this. I have:

f :: MonadIO m => ReaderT FooBar m Answer;
f = (liftIO getArgs) >>= ...

I need to run this with modified arguments. However, since m is unknown, I cannot simply use

mapReaderT (withArgs args) :: ReaderT r IO b -> ReaderT r IO b

since I need somehow to transform (withArgs args) into m for all m.

One possibility I found is to define my own withArgs, thus:

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;
};

However, this is a kludge, and specific to one function -- I would need to re-write every withX :: X -> IO a -> IO a, e.g. Control.Exception.handle

What, if any, is a better way to do this?

Edit: In the case of handle, I found Control.Monad.CatchIO. In the other case, I used yet another, briefer kludge (not worth posting) to avoid the kludge above. Still seeking a better solution!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

生寂 2024-11-25 22:00:18

您正在寻找的部分内容是将单子同态提升到单子转换器中。

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,就可以得到t m的单子同态> 使用提升机到t n

单子同态比上面强制的类型稍强,即它负责维护单子法则。

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 转换器通常可以实例化此类。例如:

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 包中。

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

为此,您可能需要遵循卢基的建议。 =)

Part of what you are looking for is a hoisting of a monad homomorphism into a monad transformer.

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)

That is to say, given a monad homomorphism f from m to n, you can obtain a monad homomorphism from t m to t n using hoist.

A monad homomorphism is slightly stronger than the types above enforce, namely it is responsible for preserving the monad laws.

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

Notice the quantifier that I snuck in the type of hoist, MonadHoist turns out to need that flexibility for almost all instances! (Reader happens to be the one case where it doesn't. Try to write MaybeT without it.)

Monad transformers can, in general, instantiate this class. For instance:

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)

We don't currently provide it in transformers or mtl package because it would require a Rank2Type, but it is pretty straightforward to implement.

If there is enough demand for it, I'll happily package it up in a monad-extras package.

Now, I said part, because while this answers the question given by the type in the topic of your post, it doesn't address the need reflected by the bulk of the text associated with your question!

For that, you probably want to follow luqui's advice. =)

心清如水 2024-11-25 22:00:18

monad-control 包将执行此操作。我认为您想要来自 Control.Monad.IO.Control

具体来说,

liftIOOp_ (withArgs newArgs) f

应该做你想做的事。您也可以使用 liftIOOp 函数举起 bracket 之类的东西。

The monad-control package will do this. I think you want the function liftIOOp_ from Control.Monad.IO.Control.

Specifically,

liftIOOp_ (withArgs newArgs) f

should do what you want. You can lift things like bracket too, with the liftIOOp function.

哥,最终变帅啦 2024-11-25 22:00:18

我相信 interleavableIO 包 解决了这个问题。 此咖啡馆主题对此进行了讨论。

I believe the interleavableIO package addresses this problem. It is discussed in this cafe thread.

岛歌少女 2024-11-25 22:00:18

看来您也可以使用 runReaderT 来获得您想要的效果:

*> :t withArgs [] (runReaderT f FooBar)
withArgs [] (runReaderT f FooBar) :: IO Answer

其中 FooBar 是一些数据构造函数,而 f 的定义如上。

It seems you can use runReaderT to get the effect you want, as well:

*> :t withArgs [] (runReaderT f FooBar)
withArgs [] (runReaderT f FooBar) :: IO Answer

where FooBar is some data constructor and f is defined as above.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文