Reputation: 41909
I'm looking at foldM
in order to gain intuition as to how it's used.
foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a
In this simple example, I simply return [Just 100]
. But, what if I want to use the b
?
ghci> foldM (\a _ -> return a) (Just 100) [1,2,3] :: [Maybe Int]
[Just 100]
I'm confused how to use the b
within (a -> b -> m a)
.
Please help me gain intuition for this function and how to use the b
.
Upvotes: 10
Views: 5755
Reputation: 152682
Here's a sort of stupid example. Suppose we wanted to sum the list, and make sure the partial sum never went over (say) 10; thus:
> let ensure p x = x <$ guard (p x)
> foldM (\a b -> ensure (<10) (a+b)) 0 [1,2,3] :: Maybe Integer
Just 6
> foldM (\a b -> ensure (<10) (a+b)) 0 [5,5,5,-10] :: Maybe Integer
Nothing
Upvotes: 16
Reputation: 101909
I believe you have a problem with foldl
and not with foldM
. foldM
is basically just a very minor variation of foldl
.
So consider:
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f x xs
What "happens" is:
- If xs == []
then x
is returned.
- otherwise f
is called as: f x (xs !! 0)
obtaining the result value y :: a
. Then f
is called as: f y (xs !! 1)
, obtaining z
. Then we go for f z (xs !! 2)
etc.
As you can see every call to f
is passed the current result up to that point and the next element from the list in input. So it's used whenever you want to reduce a list into a single value and the computation you want to do is "sequential", i.e. you compute a value from the first element, then from this value and the following element you compute the new value, and from this and the second element you compute a new one etc.
For example:
f ys x = map (+x) ys ++ [x]
foldl f [] [1,2,3]
produces:
[6, 5, 3]
Because:
f [] 1 = [1]
f [1] 2 = [1+2, 2] = [3, 2]
f [3, 2] 3 = [3+3, 2+3, 3] = [6, 5, 3]
To better understand how foldl
and foldr
work, see:
Now, foldM
is the same as foldl
but now the f :: a -> b -> a
has type f :: a -> b -> m a
. This means that the function that combine the current result with the next element is a monadic action, i.e. it can have effects.
For example, consider:
f ys x = do
let a = map (+x) ys ++ [x]
print a
return a
foldM f [] [1,2,3]
What happens is that the text:
[1]
[3,2]
[6,5,3]
gets printed and the value [6, 5, 3]
is the return value of the monadic action.
Upvotes: 6
Reputation: 10941
Just like with all folds with initializes, the b
type variable signifies that you may have a different type of thing for accumulator and the rest. For example, let's say I was repeating a string. I could do
Prelude> import Control.Monad
Prelude Control.Monad> foldM (\str n -> (putStrLn $ "Repeating string " ++ (show str) ++ " " ++ (show n) ++ " times") >> (return $ concat $ replicate n str)) "Yolo" [4,5,6]
Repeating string "Yolo" 4 times
Repeating string "YoloYoloYoloYolo" 5 times
Repeating string "YoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYolo" 6 times
"YoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYoloYolo"
As you can see the type of "Yolo"
differs from the types of 4
, 5
, and 6
. This is the same as all folds, foldM
just adds a monadic aspect.
Upvotes: 3
Reputation: 78
Notice that a
and b
can be different types. So the function can do anything with the two values as long as it can return a value of type m a
.
See the example below. This function is trying to sum up the length of all strings as long as they are not empty. If it finds any empty string, it returns Nothing
.
count :: Int -> String -> Maybe Int
count c s = if null s
then Nothing
else Just $ c + length s
Now you can try it out:
*Main> foldM count 0 ["Hello", "World"]
Just 10
*Main> foldM count 0 ["Hello", "", "World"]
Nothing
Upvotes: 3