## Some code kata – haskell while loops

In the previous post we solved the following problem using a for loop

Write three functions that compute the sum of the numbers in a given list using a for-loop, a while-loop, and recursion.

I have not found while loop primitives in the standard library but a library for this exists on hackage and it is called Control.Monad.Loops. It provides the following implementation

whileM_ :: (Monad m) => m Bool -> m a -> m () whileM_ p f = go where go = do x <- p if x then f >> go else return ()

Looking at the type signature we see that it takes a bool wrapped in a monad as a first argument and another monad which is the action as a second argument. The result, as with the for loop, is a monad containing nothing (or more correct the unit value).

Again, since we want to do stateful programming we will turn to the State monad. This time we need to keep both the remaining list and the sum within the state. A tuple seems like a natural choice.

The most complicated part is the condition. We use the get function to retrieve the current state. The get function has the following type signature

get :: MonadState s m => m s

It simply returns the state as a value wrapped within the monad. However, we want to test wether the list is empty or not. fmap or the equivalent applicative functor <$> is a function that allow us to apply an ordinary function to the value wrapped within the monad – transforming it to something else which in this case should be a boolean value indicating whether we should continue looping or not.

This is the type signature for fmap and <$> respectivly

(<$>) :: Functor f => (a -> b) -> f a -> f b fmap :: Functor f => (a -> b) -> f a -> f b

To test whether the list is empty we can then do the following (assuming that the list is stored as the first element in the state tuple)

not . null . fst <$> get

The final result, when putting this together, may look like below

import Control.Monad import Control.Monad.State whileM_ p f = go where go = do x <- p if x then f >> go else return () sumUsingWhile xs = snd $ execState loop (xs,0) where loop = whileM_ (not . null . fst <$> get) $ modify $ \(x:xs,sum) -> (xs, x+sum)