将Kleisli箭头升入IO?

时间:2012-11-22 01:09:39

标签: haskell io arrows lifting kleisli

如果我有以下两个Kleisli箭头:

stdoutProcessA :: Kleisli Maybe String (IO String)
writeToFileA :: Kleisli Maybe (FilePath, String) (IO ())

我希望能够写出像:

compile = proc src -> do
    output <- stdoutProcessA -< "..."
    writeToFileA -< ("...", output)
    ...

当然不起作用,因为StringIO String不匹配。另一方面,可以将stdoutProcessAwriteToFileA定义为Kleisli IO ...类型,但是我无法使用{{1}类型的箭头来组合它们我需要其他的东西。

我对箭头的经验不是很充实,所以我可能会遗漏一些明显的东西。如何进行上述操作?

1 个答案:

答案 0 :(得分:5)

这些箭对我来说没什么意义:

stdoutProcessA :: Kleisli Maybe String (IO String)
writeToFileA :: Kleisli Maybe (FilePath, String) (IO ())

当您可能需要Maybe (IO a)时,它们代表结果为IO (Maybe a)的函数。后一种类型表示可能失败的IO行为,而在前者中,失败或成功根本不取决于IO

合并IOMaybe的正确方法是使用MaybeT monad变换器,如下所示:

stdoutProcessA :: Kleisli (MaybeT IO) String String
writeToFileA :: Kleisli (MaybeT IO) (FilePath, String) ()

如果你将其他箭头写成Monad m => Kleisli (MaybeT m) a b,那么它们应该很好地与这些箭头组合而不需要任何提升。或者,您可以使用

lift' :: Monad m => Kleisli Maybe a b -> Kleisli (MaybeT m) a b
lift' (Kleisli f) = Kleisli $ \x -> MaybeT (return $ f x)

将您现有的Kleisli Maybe箭头提升至Kleisli (MaybeT IO)