Andi Pavllo
Andi Pavllo

Reputation: 2506

Use map instead of recursion

I have the following code, which takes a list, checks if each element's value is higher than the avg and, it that's the case, prints val - avg. I have already implemented it with recursion, I would like to transform it in order to use map function.

loop [] = return ()
loop (x:xs)
      | x > average = print (x - average) >> loop xs
      | otherwise = loop xs

Any suggestion?

Upvotes: 0

Views: 194

Answers (1)

duplode
duplode

Reputation: 34398

Note that each step of loop does two things at once: they (possibly) generate a printing action out of each element of the list and then combine that action with the remaining ones (using (>>)). If you want to write loop in terms of map, you need to disentangle these two sub-steps. For instance, you can define a function...

printDiffIfAboveAvg :: Double -> IO ()

... and then apply it to all elements of the list with map printDiffIfAboveAvg. That will give you a list of actions, of type [IO ()], which you will need to combine into a single overall action:

runAllActions :: [IO ()] -> IO ()

runAllActions already exists in the base library, in a more general version called sequence_:

sequence_ :: (Foldable t, Monad m) => t (m a) -> m ()

So you would have loop = sequence_ . map printDiffIfAboveAvg. In fact, there is also another function in the base library...

mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m ()

... which performs exactly this combination of sequence_ and map.

Upvotes: 7

Related Questions