我正在寻找一个函数,它接受一个函数(a - > a - > a)和一个[Maybe a]列表并返回Maybe a。 Hoogle没有给我任何帮助。这看起来像一个非常常见的模式,所以我问这个案例是否有最好的做法?
>>> f (+) [Just 3, Just 3]
Just 6
>>> f (+) [Just 3, Just 3, Nothing]
Nothing
先谢谢你,克里斯
答案 0 :(得分:26)
您应首先将[Maybe a]
变为Maybe [a]
,其中包含所有Just
元素(如果其中任何一个Nothing
,则会产生Nothing
)。
这可以使用sequence使用Maybe的Monad实例来完成:
GHCi> sequence [Just 1, Just 2]
Just [1,2]
GHCi> sequence [Just 1, Just 2, Nothing]
Nothing
definition of sequence等同于以下内容:
sequence [] = return []
sequence (m:ms) = do
x <- m
xs <- sequence ms
return (x:xs)
所以我们可以将后一个例子扩展为:
do x <- Just 1
xs <- do
y <- Just 2
ys <- do
z <- Nothing
zs <- return []
return (z:zs)
return (y:ys)
return (x:xs)
使用do-notation expression of the monad laws,我们可以按如下方式重写:
do x <- Just 1
y <- Just 2
z <- Nothing
return [x, y, z]
如果您知道Maybe monad是如何工作的,那么您现在应该了解sequence
如何实现所需的行为。 :)
然后,您可以使用foldr
使用(<$>)
(来自Control.Applicative;等效地,fmap
或liftM
)将此二进制函数折叠到列表中:
GHCi> foldl' (+) 0 <$> sequence [Just 1, Just 2]
Just 3
当然,您可以使用任何您想要的折叠,例如foldr
,foldl1
等。
作为额外的,如果你希望当列表为空时结果为Nothing
,从而能够省略折叠的零值而不必担心空列表上的错误,那么你可以使用这个折叠功能:
mfoldl1' :: (MonadPlus m) => (a -> a -> a) -> [a] -> m a
mfoldl1' _ [] = mzero
mfoldl1' f (x:xs) = return $ foldl' f x xs
,同样适用于foldr
,foldl
等。您需要为此导入Control.Monad。
然而,必须略微区别使用:
GHCi> mfoldl1' (+) =<< sequence [Just 1, Just 2]
Just 3
或
GHCi> sequence [Just 1, Just 2] >>= mfoldl1' (+)
Just 3
这是因为,与其他折叠不同,结果类型看起来像m a
而不是a
;它是 bind 而不是地图。
答案 1 :(得分:14)
根据我的理解,你想获得一堆maybes的总和,或Nothing
如果其中任何一个是Nothing
。这实际上非常简单:
maybeSum = foldl1 (liftM2 (+))
您可以将其概括为:
f :: Monad m => (a -> a -> a) -> [m a] -> m a
f = foldl1 . liftM2
与Maybe
monad一起使用时,f
完全符合您的要求。
如果您关心空列表,可以使用此版本:
f :: MonadPlus m => (a -> a -> a) -> [m a] -> m a
f _ [] = mzero
f fn (x:xs) = foldl (liftM2 fn) x xs
答案 2 :(得分:6)
如此简单的事情:
λ Prelude > fmap sum . sequence $ [Just 1, Just 2]
Just 3
λ Prelude > fmap sum . sequence $ [Just 1, Just 2, Nothing]
Nothing
或者,使用(+)
:
λ Prelude > fmap (foldr (+) 0) . sequence $ [Just 1, Just 2]
Just 3
λ Prelude > fmap (foldr (+) 0) . sequence $ [Just 1, Just 2, Nothing]
Nothing
所以,maybeSum = fmap sum . sequence
。