再一次,通过一些糟糕的,糟糕的编程,我已经设法让自己陷入了类型的可怕境地。
有没有办法将Either a (IO b)
转换为IO (Either a b)
?我知道,让自己陷入这种状况并不是很好的编程,所以我也愿意接受如何避免这种情况的建议。
答案 0 :(得分:5)
当然!
convert :: Either a (IO b) -> IO (Either a b)
convert = either (return . Left) (fmap Right)
现在,如果你想将IO (Either a b)
转换为Either a (IO b)
,你就会遇到麻烦,但是你没有,所以你没事。
让我们看看convert
是如何运作的:
either :: (a -> c) -> (b -> c) -> Either a b -> c
,因此它会为我们处理模式匹配,确定我们是否有a
或IO b
。a
,我们只需要将其转换为IO (Either a b)
。构造函数Left :: a -> Either a b
执行第一部分,IO
是monad,因此我们可以使用return
执行Either a b -> IO (Either a b)
。如果我们有IO b
,我们需要将其转换为IO (Either a b)
。我们可以用符号来做到这一点:
given iob = do
b <- iob
return . Right $ b
使用return . Right
作为b -> IO (Either a b)
。但这正是Monads中mapM :: Monad m => (a -> b) -> m a -> m b
的情况:given iob = mapM Right iob
。但是,大多数人都不会使用mapM
,因为它只是fmap
对Monads的专长,所以我们会使用fmap
:{{1 },或者,pointfree:given iob = fmap Right iob
。