繁体   English   中英

习惯于在haskell中汇总Maybe Int列表的方法

[英]Idiomatic way to sum a list of Maybe Int in haskell

有没有更惯用的方式来实现以下内容? 我觉得我错过了摆脱lambda的方法,但无法找到将其转换为无点的方法。 也许还有另一种非适用的方式更直接?

import Data.Maybe
import Control.Applicative

foldl (\x y -> pure (+) <*> x <*> y) (Just 0) [Just 3, Just 4]
-- Just 7

foldl (\x y -> pure (+) <*> x <*> y) (Just 0) [Just 3, Just 4, Nothing]
-- Nothing

我只是使用来自Control.Monad的sequence

> fmap sum $ sequence [Just 3, Just 4]
Just 7
> fmap sum $ sequence [Just 3, Just 4, Nothing]
Nothing

对于无点形式:

sumMaybe :: Num a => [Maybe a] -> Maybe a
sumMaybe = fmap sum . sequence

消除lambda最直接的方法是使用liftA2 ; 这正是你写的代码

liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 f x y = pure f <*> x <*> y

foldl (liftA2 (+)) (Just 0) [Just 1, Just 2]

那么我们有一些选择如何传播错误。 这段代码认为任何Nothing都会导致完全失败。 我们可以通过两个步骤来实现,比如@bhekilr建议使用sequence

sum <$> sequence [Just 1, Just 2]     sum <$> sequence [Just 1, Nothing]
Just (sum  [1,2])                     sum <$> Nothing
Just 3                                Nothing

我们还可以使用(+)在值上引入Monoid的事实,以便“忽略” Nothing s。 最字面意思是

import Data.Monoid

getSum $ foldMap (maybe mempty Sum) [Just 1, Just 2, Nothing]
-- equivalent to, but faster than
getSum . mconcat . map (maybe mempty Sum) $ [Just 1, Just 2, Nothing]
getSum . mconcat $ [Sum 1, Sum 2, Sum 0]
3

但我们也可以使用catMaybeData.Monoid分两步完成

sum . catMaybes $ [Just 1, Just 2, Nothing]
sum [1, 2]
3

我认为foldM在这里运作良好。

import Control.Monad
sumMay = foldM (fmap . (+)) 0

我认为它是最清晰的,因为它映射(Ba duh duh ching)到你在纯代码中所做的事情。

您可以通过以下方式解除Maybe Monad中的(+):

input> fold (liftM2 (+)) (Just 0) [Just 1, Just 2]
Just 3
input> fold (liftM2 (+)) (Just 0) [Just 1, Just 2, Nothing]
Nothing
import Data.Maybe
import Data.List
sumMaybes = sum . catMaybes

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM