Идиоматический способ суммирования списка 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