问题是这样的。我有:
f :: MonadIO m => ReaderT FooBar m Answer;
f = (liftIO getArgs) >>= ...
我需要使用修改后的参数来运行它。但是,由于 m 是未知的,我不能简单地使用
mapReaderT (withArgs args) :: ReaderT r IO b -> ReaderT r IO b
因为我需要以某种方式将 (withArgs args) 转换为所有 m 的 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 a -> IO a
,例如 Control.Exception.handle
如果有的话,有什么更好的方法来做到这一点?
编辑:在句柄的情况下,我找到了 Control.Monad.CatchIO。在另一种情况下,我使用了另一个更简短的拼凑(不值得发布)来避免上面的拼凑。仍在寻求更好的解决方案!