mapMonadTrans :: MonadTrans xT => (ma→nb)→ xTma-> xTnb
问题是这样的。我有:
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您正在寻找的部分内容是将单子同态提升到单子转换器中。
也就是说,给定一个从
m
到n
的单子同态f
,就可以得到t m
的单子同态> 使用提升机到t n
。单子同态比上面强制的类型稍强,即它负责维护单子法则。
请注意,我在
hoist
类型中隐藏的量词,MonadHoist
事实证明几乎所有实例都需要这种灵活性! (Reader
恰好是一种没有它的情况。尝试在没有它的情况下编写 MaybeT。)Monad 转换器通常可以实例化此类。例如:
我们目前没有在
transformers
或mtl
包中提供它,因为它需要Rank2Type
,但实现起来非常简单。如果有足够的需求,我很乐意将其打包在
monad-extras
包中。现在,我说部分,因为虽然这回答了您帖子主题中的类型给出的问题,但它并没有解决与您的问题相关的大部分文本所反映的需求!
为此,您可能需要遵循卢基的建议。 =)
Part of what you are looking for is a hoisting of a monad homomorphism into a monad transformer.
That is to say, given a monad homomorphism
f
fromm
ton
, you can obtain a monad homomorphism fromt m
tot n
using hoist.A monad homomorphism is slightly stronger than the types above enforce, namely it is responsible for preserving the monad laws.
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:
We don't currently provide it in
transformers
ormtl
package because it would require aRank2Type
, 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. =)
monad-control 包将执行此操作。我认为您想要来自 Control.Monad.IO.Control。
具体来说,
应该做你想做的事。您也可以使用
liftIOOp
函数举起bracket
之类的东西。The monad-control package will do this. I think you want the function
liftIOOp_
from Control.Monad.IO.Control.Specifically,
should do what you want. You can lift things like
bracket
too, with theliftIOOp
function.我相信 interleavableIO 包 解决了这个问题。 此咖啡馆主题对此进行了讨论。
I believe the interleavableIO package addresses this problem. It is discussed in this cafe thread.
看来您也可以使用
runReaderT
来获得您想要的效果:其中
FooBar
是一些数据构造函数,而f
的定义如上。It seems you can use
runReaderT
to get the effect you want, as well:where
FooBar
is some data constructor andf
is defined as above.