如果我有以下两个Kleisli箭头:
stdoutProcessA :: Kleisli Maybe String (IO String)
writeToFileA :: Kleisli Maybe (FilePath, String) (IO ())
我希望能够写出像:
compile = proc src -> do
output <- stdoutProcessA -< "..."
writeToFileA -< ("...", output)
...
当然不起作用,因为String
与IO String
不匹配。另一方面,可以将stdoutProcessA
和writeToFileA
定义为Kleisli IO ...
类型,但是我无法使用{{1}类型的箭头来组合它们我需要其他的东西。
我对箭头的经验不是很充实,所以我可能会遗漏一些明显的东西。如何进行上述操作?
答案 0 :(得分:5)
这些箭对我来说没什么意义:
stdoutProcessA :: Kleisli Maybe String (IO String)
writeToFileA :: Kleisli Maybe (FilePath, String) (IO ())
当您可能需要Maybe (IO a)
时,它们代表结果为IO (Maybe a)
的函数。后一种类型表示可能失败的IO
行为,而在前者中,失败或成功根本不取决于IO
。
合并IO
和Maybe
的正确方法是使用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)
。