1
votes

I have a Haskell code that has two functions:

The first function:

functionA :: [Int] -> Maybe Int

The second one:

functionB :: Int -> Maybe Int

What I want to do is to recurse on every element of [Int] and feed it into functionB. If function B returns an Int, then move to the next element, if it returns Nothing, then functionA returns nothing too.

Any idea how best to do this?

Thanks :)

3
Do you mean you want to write functionA by using functionB? What happens if more than one of the Ints gives an Int instead of Nothing? Just return the first one that worked, or return a list of all of the ones that worked?not my job

3 Answers

3
votes

You can use sequence to take [Maybe Int] to Maybe [Int]

functionA ints = sequence (map functionB ints)

Generally this combination of sequence and map is called mapM.

functionA ints = mapM functionB ints
1
votes

Your question has few things that are not clear hence I am making few assumptions. functionA is like a fold as it transform a [Int] to Maybe Int but before folding the ints it calls functionB to transform each integer into a Maybe Int where Nothing result indicate a failure in transformation and which leads to failure of the functionA and making it return Nothing.

import Control.Applicative

functionA :: [Int] -> Maybe Int
functionA nums = foldl (\x y -> (+) <$> x <*> y) (Just 0) $ map functionB nums

functionB :: Int -> Maybe Int
functionB 2 = Nothing
functionB x = Just (x+x)

In the example above, the + is used in the fold operation and functionB fails on number 2

0
votes

J. Abrahamson answered right, but he named the result function unusually and it confused you.

Let we have ints:

ints :: [a]

functionA :: [a] -> Maybe a

functionB :: a -> Maybe a

So we wish to get map functionB:

functionC :: a -> Maybe [a]
functionC ints = mapM functionB ints

but functionC has result type Maybe [a], not [a], so we use fmap

result :: [a] -> Maybe a
result ints = join $ fmap functionA $ functionC ints

And we also use join to get rid of Maybe (Maybe a) result

Or let's write in one line:

result :: [a] -> Maybe a
result = join . fmap functionA . mapM functionB

UPDATED

But in this solution always calculates all ints. If we wish to stop calculating, we need to have mapIfAllJust function, like this:

result :: [a] -> Maybe a
result = join . fmap functionA . sequence . mapIfAllJust functionB

mapIfAllJust :: (a -> Maybe b) -> [a] -> [Maybe b]
mapIfAllJust _ []     = []
mapIfAllJust f (x:xs) = go f (f x) [] xs
where
    go _ Nothing _    _         = [Nothing]
    go _ pr      used []        = pr : used
    go f pr      used (nxt:rst) = go f (f nxt) (pr : used) rst