我有一个类型a -> IO (Maybe b)
的函数,我想将其应用于IO (Maybe a)
并得到IO (Maybe b)
。我写了一个函数来做到这一点:
ioMaybeApply :: (a -> IO (Maybe b)) -> IO (Maybe a) -> IO (Maybe b)
ioMaybeApply f ioMaybeA = do
maybeA <- ioMaybeA
maybe (return Nothing) f maybeA
有没有标准的Haskell函数来做到这一点?我尝试使用Hoogle搜索,但一无所获。如果不是,我的实现是好的,还是更简单?
这可以通过MaybeT
monad 变压器来实现:
GHCi> import Control.Monad.Trans.Maybe
GHCi> :t f m -> runMaybeT (MaybeT m >>= MaybeT . f)
f m -> runMaybeT (MaybeT m >>= MaybeT . f)
:: Monad m => (a1 -> m (Maybe a)) -> m (Maybe a1) -> m (Maybe a)
import Control.Monad.Trans.Maybe
-- Making it look like your definition, for the sake of comparison.
ioMaybeApply :: (a -> IO (Maybe b)) -> IO (Maybe a) -> IO (Maybe b)
ioMaybeApply f ioMaybeA = runMaybeT $ do
a <- MaybeT ioMaybeA
MaybeT (f a)
如果您在多个地方使用此模式,那么将a -> IO (Maybe b)
函数更改为a -> MaybeT IO b
可能会有所回报 - 然后您可以使用(>>=)
和/或无缝的do-block而不是专用函数。另一方面,如果这只是一次性的,您可能会合理地认为使用MaybeT
是矫枉过正的;在这种情况下,您的实现完全没问题。
(值得一提的是,虽然有一个名为Compose
的嵌套函子的通用包装器具有Functor
和Applicative
个实例,但它没有Monad
实例,因为嵌套两个 monad 并不一定会产生可以给出合法Monad
实例的东西。既然如此,我们通常采用为每种有效的组合量身定制的单变压器。