We’re seeing an increase in distributed programming for things like multi-core CPUs and clusters. How do you feel Haskell is placed to deal with those changes?
I think Haskell in particular, but purely functional programming in general, is blazing the trail for this. I’ve got a whole one hour talk about the challenge of effect effects – which in this case actually means side effect effects. Side effects are things like doing input output, or just writing to a mutable memory location, or changing the value of the memory location.
In a normal language, like Pascal or Perl, what you do all the time is say ‘assign value 3 to x’, so if x had the value of 4 before, it has the value of 3 now. So that these locations, called x, y & z, are the names of a location that can contain a value that can change over time.
In a purely functional language, x is the name of a value that never changes. If you call a procedure in Perl or Pascal, you might not pass the procedure any arguments and you may not get any results, but the act of calling the procedure can cause it to write to disk, or to change the values of many other variables. If you look at this call to the procedure, it looks innocuous enough, but it has side effects that you don’t see. These aren’t visible in the call, but there are many effects of calling the procedure, which is why you called it. If there were no effects you wouldn’t call it at all.
In a functional language, if you call a function f, you give it some arguments and it returns a result. All it does is consume the arguments and delivers the result. That’s all it does – it doesn’t create any other side effects. And that makes it really good for parallel evaluation in a parallel machine. Say if you call f of x and then you add that result to g of y in a functional language, since f doesn’t have any side effects and g doesn’t have any side effects, you can evaluate the calls in parallel.
So the message is that purely functional programming is by default, safe for parallel programming, and mainstream programming is by default dangerous
But in a conventional mainstream programming language, f might have a side effect on a variable that g reads. f might write a variable behind the scenes that g looks at. It therefore makes a difference whether you call f and then g or g and then f. And you certainly can’t call them at the same time!
It’s actually really simple. If the functions that you call do not have any side effect effects behind the scenes, if all they do is compute a value from the input values that you give them, then if you have two such things, you can clearly do them both at the same time. And that’s purely functional programming. Mainstream languages are, by default, dangerous for parallel evaluation. And purely functional languages are by default fine at parallel evaluation.
Functional, whether lazy or non-lazy, means no side effect. It doesn’t mess about behind the scenes – it doesn’t launch the missiles, it doesn’t write to the disk. So the message of the presentation I mentioned before is that purely functional programming is by default, safe for parallel programming, and mainstream programming is by default dangerous.
Now, that’s not to say that you can’t make mainstream programming safer by being careful, and lots and lots of technology is devoted to doing just that. Either the programmer has to be careful, or is supported by the system in some way, but nevertheless you can move in the direction of allowing yourself to do parallel evaluation.
The direction that you move in is all about gaining more precise control about what side effects can take place. The reason I think functional programming languages have a lot to offer here is that they’re already sitting at the other end of the spectrum. If you have a mainstream programming language and you’re wanting to move in a purely functional direction, perhaps not all the way, you’re going to learn a lot from what happens in the purely functional world.
I think there’s a lot of fruitful opportunities for cross-fertilization. That’s why I think Haskell is well placed for this multi-core stuff, as I think people are increasingly going to look to languages like Haskell and say ‘oh, that’s where we can get some good ideas at least’, whether or not it’s the actual language or concrete syntax that they adopt.
All of that said however – it’s not to say that purely functional programming means parallelism without tears. You can’t just take a random functional program and feed it into a compiler and expect it to run in parallel. In fact it’s jolly difficult! Twenty years ago we thought we could, but it turned out to be very hard to do that for completely different reasons to side effects: rather to do with granularity. It’s very, very easy to get lots of very, very tiny parallel things to do, but then the overheads of doing all of those tiny little things overwhelm the benefits of going parallel.
I don’t want to appear to claim that functional programmers have parallel programming wrapped up – far from it! It’s just that I think there’s a lot to offer and the world will be moving in that direction one way or another.
You obviously had some foresight twenty years ago…
I don’t think it was that we were that clairvoyant – it was simply about doing one thing well…