for

while

for

while

for-each

yield



// In C

for (int i = 0; i < n; i++)

list[i]++



-- In Haskell

incList (x:xs) = 1+x : foo xs

incList [] = []





incList = map (+1)



iterate-over-list

map



map f (x:xs) = f x : map f xs

map f [] = []





-- in C

int total = 0;

for (int i = 0; i < n; i++)

total += list[i];



-- in Haskell

sum [] = 0

sum (x:xs) = x + sum xs



-- or using the built in foldl

sum = foldl (+) 0



foldl

for

for

f

x



int x;

while (1) {

int x2 = f(x);

if (x == x2) break;

x = x2;

}



fix f x = if x == x2 then x else fix f x2

where x2 = f x



f

x

fix

lambda

simplify

inline

specialise

lambda

simplify

lambda



fixList orig x = f orig x

where

f [] x = x

f (a:as) x = if x == x2 then f as x else f orig x2

where x2 = a x



fixList [lambda,simplify,inline,specialise]



fixList



int x, x2;



begin:

x = x2;



x2 = lambda(x) ; if (x != x2) goto begin;

x2 = simplify(x) ; if (x != x2) goto begin;

x2 = inline(x) ; if (x != x2) goto begin;

x2 = specialise(x); if (x != x2) goto begin;



n

int

inline

In normal programming languages, there are many keywords for, such asetc. These flow control keywords encode a particular pattern of iteration, such as looping over a range (in the case of) or continuing until some condition holds (). Imperative programming languages continue to add more iteration keywords: both C#/Java have introduced some form of; Python/C# have; Ada has many variants.Haskell doesn't have these iteration keywords, but instead relies on recursion. This choice, when coupled with a few other Haskell ingredients, makes it much more powerful. Take for example the task of looping over a sequence, adding 1 to each element:I've used C mutating an array, and Haskell allocating a new list, simply because that would be the natural thing to do in each language. However, the great thing about higher-order functions is that we can now go back and abstract the flow control in Haskell, giving us:The above function maps over a list, incrementing each element. People have identified a common pattern (iterating over a list) and rather than baking it into the language with a keyword such as, a library function can provide the operation. It is very important thatis not special in any way, and can simply be defined as:The great advantage is that rather than being restricted to a limited range of flow control operators that someone somewhere decided upon, we can add new ones. Let's take another example, that of summing a list:In Haskell there is a standard library functionwhich iterates over a list using an accumulator, managing updates to the accumulator for you, and setting an initial value. In C there is no such operator, so the more general purposeis used.But these examples are very common, so C'skeyword has provided most most of the control flow. However, sometimes you need more exotic flow control, which the authors of the language did not think of including. Take the example of computing a fixed point of a functionon the valueHere the Haskell version shows its power, instead of having defined a particular instance for a particularand a particular type of value, in Haskell we have basically definedas a new form of flow control.In C we were still able to define something, but it was much harder. Now consider the following example that I was working on yesterday. I have an algorithm which has 4 stages,. Each stage must be run in turn, but if any stage changes something, then we restart from the beginning. For example, we apply, then- if something changes we restart at. We only finish once all the stages have been run without changing anything. In Haskell this code is simple:I define a new function called, which provides an abstraction of flow control. The actual operations have been well isolated from this structure. I considered how to express this in structured C and drew a complete blank. My best guess is:It might be possible to change some of this flow control into a macro, but I can think of no clean abstraction. Haskell is a great language for building abstractions, flow-control is just one highly useful instance.Some of the code in this article isn't quite as nice as I'd wanted it to be, and isn't really a fair comparison. The array processing code in C relies on having definedto be the length of the list, and having that tracked separately. The fixed point definition on C works overto get a nice equality test, but that is merely a limitation of the language not having a standardized way to do equality. The C code could use function pointers, but in realitytakes an extra argument so is used as a closure in Haskell - and besides, that would hardly be the standard way of coding C.