Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loop through a set of functions with Haskell

Here's a simple, barebones example of how the code that I'm trying to do would look in C++.

while (state == true) {
  a = function1();
  b = function2();
  state = function3();
}

In the program I'm working on, I have some functions that I need to loop through until bool state equals false (or until one of the variables, let's say variable b, equals 0).

How would this code be done in Haskell? I've searched through here, Google, and even Bing and haven't been able to find any clear, straight forward explanations on how to do repetitive actions with functions.

Any help would be appreciated.

like image 679
subtlearray Avatar asked Dec 01 '25 05:12

subtlearray


2 Answers

Taking Daniels comment into account, it could look something like this:

f = loop init_a init_b true
    where
         loop a b True = loop a' b' (fun3 a' b')
             where
                 a' = fun1 ....
                 b' = fun2 .....
         loop a b False = (a,b)
like image 95
Ingo Avatar answered Dec 03 '25 21:12

Ingo


Well, here's a suggestion of how to map the concepts here:

  • A C++ loop is some form of list operation in Haskell.
  • One iteration of the loop = handling one element of the list.
  • Looping until a certain condition becomes true = base case of a function that recurses on a list.

But there is something that is critically different between imperative loops and functional list functions: loops describe how to iterate; higher-order list functions describe the structure of the computation. So for example, map f [a0, a1, ..., an] can be described by this diagram:

[a0,   a1,   ..., an]
 |     |          |
 f     f          f
 |     |          |
 v     v          v
[f a0, f a1, ..., f an]

Note that this describes how the result is related to the arguments f and [a0, a1, ..., an], not how the iteration is performed step by step.

Likewise, foldr f z [a0, a1, ..., an] corresponds to this:

f a0 (f a1 (... (f an z)))

filter doesn't quite lend itself to diagramming, but it's easy to state many rules that it satisfies:

  • length (filter pred xs) <= length xs
  • For every element x of filter pred xs, pred x is True.
  • If x is an element of filter pred xs, then x is an element of xs
  • If x is not an element of xs, then x is not an element of filter pred xs
  • If x appears before x' in filter pred xs, then x appears before x' in xs
  • If x appears before x' in xs, and both x and x' appear in filter pred xs, then x appears before x' in filter pred xs

In a classic imperative program, all three of these cases are written as loops, and the difference between them comes down to what the loop body does. Functional programming, on the contrary, insists that this sort of structural pattern does not belong in "loop bodies" (the functions f and pred in these examples); rather, these patterns are best abstracted out into higher-order functions like map, foldr and filter. Thus, every time you see one of these list functions you instantly know some important facts about how the arguments and the result are related, without having to read any code; whereas in a typical imperative program, you must read the bodies of loops to figure this stuff out.

So the real answer to your question is that it's impossible to offer an idiomatic translation of an imperative loop into functional terms without knowing what the loop body is doing—what are the preconditions supposed to be before the loop runs, and what the postconditions are supposed to be when the loop finishes. Because that loop body that you only described vaguely is going to determine what the structure of the computation is, and different such structures will call for different higher-order functions in Haskell.

like image 25
Luis Casillas Avatar answered Dec 03 '25 22:12

Luis Casillas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!