I want to write a loop in haskell using monads but I am having a hard time understanding the concept.
Could someone provide me with one simple example of a while loop while some conditions is satisfied that involves IO action? I don't want an abstract example but a real concrete one that works.
Below there's a horrible example. You have been warned.
Consider the pseudocode:
var x = 23
while (x != 0) {
print "x not yet 0, enter an adjustment"
x = x + read()
}
print "x reached 0! Exiting"
Here's its piece-by-piece translation in Haskell, using an imperative style as much as possible.
import Data.IORef
main :: IO ()
main = do
x <- newIORef (23 :: Int)
let loop = do
v <- readIORef x
if v == 0
then return ()
else do
putStrLn "x not yet 0, enter an adjustment"
a <- readLn
writeIORef x (v+a)
loop
loop
putStrLn "x reached 0! Exiting"
The above is indeed horrible Haskell. It simulates the while loop using the recursively-defined loop
, which is not too bad. But it uses IO everywhere, including for mimicking imperative-style mutable variables.
A better approach could be to remove those IORef
s.
main = do
let loop 0 = return ()
loop v = do
putStrLn "x not yet 0, enter an adjustment"
a <- readLn
loop (v+a)
loop 23
putStrLn "x reached 0! Exiting"
Not elegant code by any stretch, but at least the "while guard" now does not do unnecessary IO.
Usually, Haskell programmers strive hard to separate pure computation from IO as much as possible. This is because it often leads to better, simpler and less error-prone code.