Идиоматический способ суммирования списка Maybe Int in haskell

Есть ли более идиоматический способ реализовать следующее? Я чувствую, что мне не хватает средств, чтобы избавиться от лямбды, но не смог понять, как преобразовать его в бесконтактный. Может быть, есть еще один неприменимый способ, который более прямой?

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

Ответ 1

Я бы просто использовал sequence из Control.Monad:

> 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

Ответ 2

Самый прямой способ устранить лямбда - использовать 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

Мы также можем использовать тот факт, что (+) индуцирует a 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

Но мы также можем использовать catMaybe из Data.Monoid для этого в два этапа

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

Ответ 3

Я думаю, что foldM хорошо работает здесь.

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

Я думаю, что это яснее всего, когда он отображает (Ba duh duh ching), что вы делаете в чистом коде.

Ответ 4

Вы можете поднять (+) в Maybe Monad с помощью:

input> fold (liftM2 (+)) (Just 0) [Just 1, Just 2]
Just 3
input> fold (liftM2 (+)) (Just 0) [Just 1, Just 2, Nothing]
Nothing

Ответ 5

import Data.Maybe
import Data.List
sumMaybes = sum . catMaybes