Functional programming is mainly a style, just like OO programming. Some languages are created with this style in mind (Haskell, ML, Scheme, etc. for functional; Java, C#, C++, etc. for OO), but the principles can be applied to most languages.
I'd say start with a language your already comfortable with, preferably the "most functional" (eg. if you know C and Python, go with Python since it has first class functions). As you learn about functional programming principles (no mutable state, no side-effects, etc.) try following them in your language of choice.
The best advice I can give is to think in terms of values rather than statements. Imperative programming is all about "which action should I perform next?", whereas functional programming is all about "what do I want this to be?". This manifests in a lot of places, some of which I've mentioned below. The difference can be summed up by the following:
// An imperative mindset performs a series of actions
// Check the value of "foo"
if (foo) {
// Set the value of "bar"
bar = FALSE;
}
else {
// Set the value of "bar"
bar = TRUE;
}
// A functional mindset asks what value "bar" should have
// "bar" is the opposite of "foo"
bar = !foo;
Here are a few ways to become more "value-oriented":
- Static Single Assignment: define new variables instead of mutating existing ones. Mutating variables is a symptom of imperative thinking ("then do this"), whereas defining a load of constant values is a symptom of value thinking ("I'll need this as well").
- Pretend you're using lazy evaluation: if your code is defining a value, it will work under any evaluation strategy (assuming it halts). If your code is highly imperative, it will break under lazy evaluation (since it's effectively 'executed backwards').
- Separate functions from procedures: try to make each function you write either calculate a value (ie. a pure function) OR perform some side-effect (ie. a procedure) but not both. This way all of your calculations can focus on their result value, rather than worrying about interleaving of effects.
- Factor out common function-chaining patterns like maps, folds, unfolds, zips, etc. If your language has first-class functions (or hygenic macros) then you'll learn to appreciate them. If not, you'll learn to want them!
- Use ternary expressions: in imperative languages, if/then/else is used to send execution down different paths, which is a very non-functional thing to do. Instead of choosing different actions to perform, try using ternary operators to choose different values to assign. I'd recommend using extra variables rather than nesting them though, since they can get difficult to understand (just like the branching logic of an imperative program).
- Use lookup tables instead of switch statements: if your language supports first-class functions, why not try this
(In PHP):
// Imperative
switch ($foo) {
case 0:
zero();
case 1:
one();
break;
default:
def();
}
// Functional
$table = NULL;
$table = [
function() use (&$table) {
zero(); call_user_func($table[1]);
},
'one'];
call_user_func(
array_key_exists($foo, $table)? $table[$foo]
: 'def');
- Use recursion instead of loops: be careful, as you might overflow your stack! Then you'll appreciate tail-call optimisation. Many languages have built-in "map", "reduce" (AKA "fold"), etc. which don't have this problem. If not, you can define these yourself using loops then never have to write another loop again.
- Group related values together: for example, an if statement which sets different values for "x", "y" and "z" could be turned into a ternary statement which chooses between dictionaries containing keys "x", "y" and "z".
- Use pattern-matching to break down values, for example:
(In PHP):
// Imperative
if ($foo) {
$x = 'hello';
$y = 'world';
$z = 'wibble';
}
else {
$x = 'some';
$y = 'different';
$z = 'strings';
}
// Functional
list($x, $y, $z) = $foo? ['hello', 'world', 'wibble']
: ['some', 'different', 'strings'];
- Use comprehensions: these are inherently functional, since they're a mixture of maps and filters, and are a quick way to get into a functional way of thinking. For example:
(In Python):
results = [foo(x) for x in bar if baz(x)]
- Use values to represent effects: instead of calling procedures deep within your application, you can instead make a note of the procedure you want to call and put those notes into your return value. For example, instead of calling "foo" with "x", "y" and "z" you could return a list "[("foo", x), ("foo", y), ("foo", z)]}" and get the caller to run them for you. Applying this same principle, the caller can instead put them into its return value and pass them up to its caller, and so on. This way, lots of your procedures become pure functions: they're calculating a list of procedures to call, rather than calling procedures directly. This may sound silly at first, but it's basically an inverse of dependency-injection. It's a bit more boilerplate, but it offers some nice advantages: behavioural tests don't need mock objects (just look at the procedure-list), more code is unit-testable since it doesn't cause effects, procedures can be ignored/rearranged/decorated/retried, etc. Note that this is a form of message queue, and also an instance of the "command pattern".
- Factor out pattern in your procedure-lists: "I don't care about the results, just run them in this sequence" is exactly what functional programmers call a Functor; "Chain these together so the result of the nth procedure is sent into the (n+1)th procedure" is exactly what functional programmers call an Applicative Functor; "The nth procedure could be this or that, depending on what the (n-1)th precedure returns" is exactly what functional programmers call a Monad.
In my opinion, these are good programming practices anyway. Once you're used to them, you'll find that languages desgined for functional programming (eg. Haskell) make these practices much easier (eg. they have tail-call optimisation, they make mutable variables explicit, they have very powerful pattern matching and comprehensions, etc.)