One of the promises of functional programming has only recently started to appear, and it’s still very difficult to achieve in practice. Consider the following snippet of C code:
a = someCalculation() + anotherCalculation();
In C, either of these routines may have side effects, so they must be executed sequentially. In a functional language, however, they may not. This means that they may be executed in either order. In fact, in a language with lazy evaluation like Haskell, they may not be evaluated until the value of a is actually used.
Because they can be executed in either order, they can also be executed concurrently. If they are both very small functions, there isn’t much benefit in this, but if they are very time-consuming things, then there is.
In a functional language, this transform is trivial for the compiler to do. The difficult bit is deciding when to do it. Running every function call in parallel will almost certainly be slowereven on a massively parallel machinethan running them all sequentially just because of the overhead involved in creating, or communicating with, all of the threads.
That said, current compilers are starting to make good progress in this respect. It’s much easier in an environment that does runtime code generation. You can start at the top level and profile each function call, then as each function is re-run, profile at a finer granularity until you find places that can benefit from parallelism.
This is where the promise of functional programming is really great. A lot of the low-hanging fruit has already been harvested. When most people think of functional programming, they think of higher-order functions like map, which take a function and a collection as arguments, apply the function to each element in the collection, and return the result. These can be parallelized trivially, and are even in some imperative programming languages.
For example, NSArray in Objective-C has a -enumerateObjectsWithOptions:usingBlock: method. This takes a block (effectively a function) as an argument and executes it with each of the elements in the collection. If one of the options is NSEnumerationConcurrent, then it will do this in parallel. I talk about this in a bit more detail in the second edition of the Objective-C Phrasebook, so I won't say any more about it in an article that's meant to be about functional programming languages.
This, however, highlights one of the reasons why it’s worth keeping an eye on functional languages even if you don't use them: Ideas from them often migrate into other languages and can be used quite effectively.
In fact, GCC and Clang both provide annotations that allow you to specify that a C “function” is a real function, which allows the compiler to perform extra optimizations, such as deleting multiple calls with the same arguments.