Posted on December 29, 2014

The sum of a list of numbers

When trying to explain the difference between functional programming languages and imperative languages, one of the examples people usually give is the sum of a list of numbers.

Someone will say, for example, that in Haskell the sum of a list of numbers can be calculated like this:

    sum [1..10]

And the thesis is normally that this is much simpler and more elegant than doing a for loop, like so:

    in sum = 0;
    for(int x=1; x<=10; x++){
        sum += x;
    }

Now, I was never convinced with this example. Because, let’s be honest – I can easily create a function (in javascript) or method (in java) which receives two parameters and returns an array of numbers. And likewise I can create a function which receives an array and sums all of its elements.

in javascript I can even do it natively with reduce:

    function sum(array){
        return array.reduce(prev, cur){
            return prev + cur;
        }
    }

and create an array generator like this:

    function range(bottom, top){
        var x, arr=[];
        for(x=bottom; x<=top; x++){
            arr.push(x);
        }
        return arr;
    }

and now I also have:

    sum(range(1,10))

And that’s also elegant and simple.

So what’s the difference really?

It may seem that the difference is that in a functional programming language you don’t have to create any of this - the language gives it to you by design. But this is not only a matter of convenience, about you not having to write these functions and have them natively in the SDK.

It’s more subtle than this.

Because these functions are there natively, you are encouraged (sometimes forced or restricted) to solve problems using this style of programming.

Haskell, for example, gives you lazy ranges and function composition as part of its default SDK. The building blocks it provides are not loops or variable assignments – it’s only resources which force you to think and solve the problem functionally, in a way that avoids state and (in Haskell’s case) in a lazy, pure way.

And that’s the difference.

In the end, we can always write any program in any language or style. Would we be real purists and we would all be writing in assembly since that is, after all, the closest we have to the von Neumann architecture computers use.

But we use higher-level languages, because they are closer to our way of thinking. And these languages provide us with some abstractions that make it easier to compose solutions to the problems we have to solve.

And that’s what functional programming gives you – the tools it provides are not higher-level versions of the von Neumann architecture, like loops and switch/cases and goto statements or variables which are like computer registers.

The tools it gives you are more mathematical, more declarative, independent from the underlying architecture, promoting solutions which are humanly describable, in a style which promotes composability, and forces you to think of what you want to accomplish – not how you want to do it.

That’s why it’s more elegant to state

To sum all the numbers from 1 to 10, first get all the numbers from 1 to 10 and then give them to a function which sums them. That is the result.

instead of stating

define a variable to keep my count and another variable for an iterator; now iterate over all the numbers from 1 to 10 and for each of them add it to the count variable. at the end of the loop, the result is in the count variable.

And that’s the difference between sum [1..10] and the sum(range(1,10)).