I am really new to Haskell, so this might be a stupid question. I have a function
foo :: Int -> IO ()
whose result will print some useful information. Now I want to do this:
do
foo 0
foo 1
foo 0
foo 2
foo 3
How can I write this as a loop? My problem is to 'concatenate' the Monads, which is done automatically by the do statement...
Thank you for your help!
Haskell - Monads. Monads are nothing but a type of Applicative Functor with some extra features. It is a Type class which governs three basic rules known as monadic rules. Left Identity Law − The return function does not change the value and it should not change anything in the Monad.
When the builtin traversals don’t obviously provide something you actually want, the end-all solution is the tail-recursive loop. This is the most manual way to loop in Haskell, and as such it’s the most flexible.
In Haskell, the sequencing can be done using the standard monadic functions: assemblyLine::Wood->TrayWrappedChopsticksassemblyLinew=(returnw)>>=makeChopsticks>>=polishChopsticks>>=wrapChopsticks or using the built in Haskell "do" notation for monads:
However, values in the IO monad are often called I/O actions and we will use that terminology here. In Haskell, the top-level mainfunction must have type IO (), so that programs are typically structured at the top level as an imperative-style sequence of I/O actions and calls to functional-style code.
mapM_ foo [0,1,0,2,3]
will do the trick.
What's perhaps more important is "how does one figure that out?" Hoogle is a wonderful tool. You want to apply a function with signature Int -> IO ()
to a bunch of Int
s to get a new IO action. The thing you're looking for will thus have signature (Int -> IO ()) -> [Int] -> IO ()
, so we go and ask Hoogle for functions with that signature. The second result is mapM_
, whose signature is
Monad m => (a -> m b) -> [a] -> m ()
Right, so mapM_
in fact works with any monad (not just IO
) and any type (not just Int
). When you think about it, that's not surprising at all.
You want the mapM_
combinator, which maps a function returning a monadic value over a list, and uses the bind operator to sequence the results:
>> let foo n = putStrLn (show n ++ "!")
>> mapM_ foo [0,1,0,2,3]
0!
1!
0!
2!
3!
Sometimes people like to use the flipped version
for :: Monad m => [a] -> (a -> m b) -> m ()
for = flip mapM_
which looks more like imperative code:
>> for [1..5] $ \n ->
putStrLn ("Number: " ++ show n)
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5
Note that a combinator called forM_
is defined in Control.Monad
and does exactly the same thing as the combinator I've called for
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With