0

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.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
domoremath
  • 555
  • 2
  • 8
  • 17
  • Does [this question](http://stackoverflow.com/questions/17719620/while-loop-in-haskell-with-a-condition) help? – Mephy Feb 13 '17 at 21:37
  • 1
    Possible duplicate of [While loop in Haskell with a condition](http://stackoverflow.com/questions/17719620/while-loop-in-haskell-with-a-condition) – jberryman Feb 13 '17 at 21:39
  • I already saw that but is there one even simpler where I can easily tell what the program is trying to compute immediately. – domoremath Feb 13 '17 at 21:41
  • 5
    Do you have an example of an imperative while loop that you can't convert? – Lee Feb 13 '17 at 21:51
  • @Lee Say something very simple like if some condition is satisfied, you keep printing "satisfied" while updating the condition. I don't want a straightforward recursion but something using monads. – domoremath Feb 13 '17 at 22:19

1 Answers1

7

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 IORefs.

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.

chi
  • 111,837
  • 3
  • 133
  • 218