I want to create a function that receives some items to process, returning Nothing
when none of the items could be processed and Just
if at least one item was processed.
To me, this sounds a lot like how traverse
works for Maybe
, but inverted, since it returns Nothing
if at least one item was not processed and Just
when all items were processed.
Supposing traverseI
is my 'inverted' traverse:
myFunc :: [Int] -> Maybe [Int]
myFunc xs = traverseI (\x -> if x > 5 then Just (x 1) else Nothing) xs
myFunc [1, 3, 6, 9] -- Just [7, 10]
myFunc [1, 2, 3] -- Nothing
I'm guessing I could mapMaybe
the values and check later if it has at least one item, but I'm wondering if there's a more 'elegant' solution.
Edit: What I'm looking is for some way to get an equivalent of this function:
traverseI :: (a -> Maybe a) -> [a] -> Maybe [a]
traverseI _ [] = Nothing
traverseI f (x:xs) = do
let mh = f x
let mt = traverseI f xs
case mh of
Nothing -> mt
Just h -> case mt of
Nothing -> Just [h]
Just t -> Just (h:t)
CodePudding user response:
There are multiple functions in Data.Maybe which might be useful. You could start with mapMaybe
:: (a -> Maybe b) -> [a] -> [b]
:
import Data.Maybe
f x = if x > 5 then Just (x 1) else Nothing
xs = [1, 3, 6, 9]
mapMaybe f xs -- [7,10]
Just $ mapMaybe f xs -- Just [7,10]
CodePudding user response:
Because Maybe [a]
is kind of a weird type, you are unlikely to find a standard library function that does this, so you'll need to write your own... which you've already done. I don't see anything wrong with your traverseI
, really.
If you'd like something more succinct, then the following will work:
import Data.Maybe
traverseI :: (a -> Maybe a) -> [a] -> Maybe [a]
traverseI f xs = case mapMaybe f xs of
[] -> Nothing
xs -> Just xs
The reason that Maybe [a]
is a "weird" type, at least for this particular application, is that the simpler type [a]
already allows for a value, namely the empty list []
, that can represent the situation where none of the items can be processed. This type is already powerful enough and doesn't "need" the extra Maybe
wrapper and its associated Nothing
value.