Home > OS >  Inverted [Maybe a] tranverse behavior
Inverted [Maybe a] tranverse behavior

Time:10-11

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.

  • Related