Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing a loop in Haskell

Tags:

haskell

I'm curious about implementing a loop in Haskell. How can I do something similar in Haskell (pseudo-code):

var i = 0
for (int i1 = 0; i1 < 10; i1++) {
  println(i1)
  i += 2
}

println(i)
like image 673
Incerteza Avatar asked Sep 13 '26 06:09

Incerteza


2 Answers

In functional terms what you are doing is folding over a list of integers so that for each integer you print the element and increase an accumulator by 2. Since we are printing something (i.e. doing I/O) we need to fold in a monad but otherwise it's just your standard left-fold.

foldM (\i i1 -> print i1 >> return (i + 2)) 0 [0..9] >>= print

We fold with a lambda function that uses the same variable names as your code. I.e. i1 is the current element and i is the accumulator.

The next parameter is the initial value for the accumulator which corresponds to i = 0 in your code.

The final parameter is the (inclusive on both ends) list of numbers we fold over.

The >>= (bind operator) pipes the result of the fold (i.e. the final value of the accumulator i) to the print function.

EDIT: This is assuming that you meant to write

var i = 0
for (int i1 = 0; i1 < 10; i1++) {
  println(i1)
  i += 2
}

println(i)

instead of incrementing just i in both the for-clause and loop body.

like image 81
shang Avatar answered Sep 14 '26 22:09

shang


Going by the two assumptions that

  1. By "similar" you mean similar in behaviour, and
  2. (the same assumption shang made) that you want to print out

    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    20
    

I would in Haskell write

do
  let xs = [0..9]
  mapM_ print xs
  print (length xs * 2)

You see how the original computation got split up into three separate (and independent!) computations.

  1. We turn the loop variable i1 into a list. We know the bounds are 0 and 9 inclusive, so the loop variable can be represented by the list [0..9].
  2. We print the contents of the list, which is the same thing as printing the loop variable every iteration.
  3. We calculate "i" from what we know about the list, and then print it as well.

The third computation is especially interesting, because it highlights the difference between traditional imperative programming and Haskell, which is a lot about declarative programming.

Adding two to a number every iteration of a list is the same thing as taking the length of the list and multiplying it by two. The big difference, in my eyes, is that I can read i = length xs * 2 and understand what it means in the blink of an eye. Counting i up every iteration of a loop, however, takes some thinking to understand what it really means.

The fact that all three sub-computations are independent means they are a lot easier to test – you can test them one at a time and if they work individually, they will work together as well!

If you meant "similar" in the sense of "similar-looking code", refer to any of the STRef/IORef answers.

like image 28
kqr Avatar answered Sep 14 '26 23:09

kqr