Wednesday, December 21, 2011

Functional Programming in PHP

All curious but “doomed” with PHP wonder about the outside world from time to time. Do you? :)

What are other ways to do things, for what kind of tasks they are better and why. I bet you all heard about Functional Programming and wanted to try but those weekends you got are not long enough and you’re “stuck with PHP” during the week.

While I still encourage you to try something like Haskell (my favorite) and find out more about this whole thing... what I’m going to do today is to try and do some Functional Programming in PHP.



What is Functional Programming

As usually, an excerpt from wiki to get started:

functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data. It emphasizes the application of functions, in contrast to the imperative programming style, which emphasizes changes in state

If I were to define it in my own words I would do it comparing the imperative approach to programming with the functional one. In the first case you reason about solving a problem step by step, like this:

Imperative getting into the house solution:

  1. get the keys out of the pocket
  2. pick the right key
  3. open the door with the key
  4. enter the house


Functional getting into the house solution:

  • enter the house
    • through the door opened
      • with the right key
        • chosen from all the keys you get out of the pocket


Now, something we understand better:

The PHP code

Read the comments in the code:


// Source "data" for the application

// Here is the pocket in which amongst other things we have our keys.
$pocket = array('keys' => array(
                  'carkey'   => 'The Car Key',
                  'housekey' => 'Home Sweet Home',
                  'workkey'  => 'Office'));

// This is the house we need to enter, as you see it's empty without us.
$house = 'empty';

// The door is closed now and to have it opened you must use the right key
$door = 'closed';

/* Imperative entering the house solution */

// Here is where I start. I start with getting the keys out of the pocket
get_keys();
// Next, the program must choose the right key
pick_the_right_key();
// Step 3: we open the door
open_door();
// Finally, enter the house
enter_house();

// checking if it worked:
echo $house; // should echo "full"

// implementation

function get_keys() {
    global $pocket, $keys;
    $keys = $pocket['keys'];
}

function pick_the_right_key() {
    global $keys, $theRightKey;
    $theRightKey = $keys['housekey'];
}

function open_door() {
    global $door, $theRightKey;
    if ($theRightKey == 'Home Sweet Home') {
        $door = 'open';
    }
}

function enter_house() {
    global $house, $door;
    if ($door == 'open') {
        $house = 'full';
    }
}


So, we have some “state” in which our house, door and the pocket are. We change this state in order to achieve our goal. Step by step.

Some of you might object that it is bad to use globals. Well, sure it is. That’s just to illustrate the approach. Most of PHP developers in most of the so-called “object-oriented” projects still utilize the state heavily: singletons, statics, “registry pattern”. Globals even.

A tiny bit of you may still object that you actually never use any of those and only do Dependency Injection and use new fancy frameworks like Symfony 2. Well, my friends, you already using functional programming to some degree! Dependency Injection (or parametrization) is a step in that direction anyway.

In fact, we all do. I personally think and like to say that “Object Oriented Programming” when done correctly (as it was supposed to be done) is closer to functional style than imperative or procedural.

What’s more interesting is that there is few languages that are “paradigm specific”. Functional techniques are slowly getting soaked into many of them nowadays, including PHP. But we’ll talk about techniques later.

Let’s get back to the way we reason about problem solving using Functional Programming:


// Source "data" for the application

// Here is the pocket in which amongst other things we have our keys.
$pocket = array('keys' => array(
                  'carkey'   => 'The Car Key',
                  'housekey' => 'Home Sweet Home',
                  'workkey'  => 'Office'));

// This is the house we need to enter, as you see it's empty without us.
$house = 'empty';

// The door is closed now and to have it opened you must use the right key
$door = 'closed';

/* Functional entering the house solution (it isn't this big actually, I just left too many comments :) ) */

echo // echoing the house state after we entered it, will echo "full"
    enter_house( // We start by defining what we want our program to do i.e. enter the house
        // we specify what we have:
        $house, // the house that we need to enter
        $door, // the door through which the house may be entered
        $pocket // our pocket full of different little things
    );

// See, no "steps" here, just one function call. Here goes the Implementation:

function enter_house($house, $door, $pocket) {
    return // In order to enter the house, we need:
        // try to open the door with the a key found in the pocket
        open_door($door, find_key($pocket))
            // and if it worked
            == 'open'
                // enter the house:
                ? 'full'
                // otherwise - leave it as it was
                : $house;
}

// we defined what enter_house is, now we go deeper defining new functions we introduced

function open_door($door, $key) {
    return // in order to open the door
        // we need the key to be right
        $key == 'Home Sweet Home'
            ? 'open'
            // if it isn't - we leave the door as it was
            : $door;
}

// now let's take a look at finding a key

function find_key($pocket) {
    return
        // amongst all keys in the pocket, we need to choose the right one
        pick_the_right_key($pocket['keys']);
}

function pick_the_right_key($keys) {
    return
        // the housekey is the right one
        $keys['housekey'];
}


Notice: we start with “entering the house”. That is, without knowing what we’ll have to do to actually enter it. Feel the ease of prototyping a program. In imperative programming you have to think trough all the steps and make sure they will get you where you need to be. In functional programming: you know where you need to be and you try to express what needs to be done for that.

“Functional” is the way you reason about solving a problem. In order to use functional programming you don’t necessary need special tools - you just need to think right. ;)

However if a language lacks particular features it may be not worth it to use it for Functional Programming or any other paradigm the language is not supposed to be used for. So let’s review some of the characteristics and features that “make a language a functional one” and what we can do with good old PHP.

I won’t go deep with definitions and focus instead on PHP-specific details. I will provide links to Wikipedia pages so you can fill in the gaps if needed.

Pure functions, immutable data

Pure functions are those that have no side-effects and for any given set of parameters always return the same result. While in languages like Haskell all functions are pure whether you want it or not, that’d be too much to ask from PHP. ha ha.

So what I suggest for PHP developers is to make functions pure when possible. Try to isolate impure stuff (where all the bugs happen). For that, you need to follow these two leads:

  • avoid state
  • avoid mutable data


By “application or system state”, we mostly refer to Input/Output operations, working with data storages and external services - that kind of stuff. Try to separate application logic from everything state-related. Whenever possible.

There is not much you can do to avoid mutable data in PHP. That’s not too bad, just make sure your pure functions are pure when treated as a “black box”.

Now, I have a fun exercise to help you :). When you create a function, type “return” the next line. This way you :

  1. don’t have much place to create mutable data
  2. are forced to introduce new functions to keep the code sane


For instance, you could have that enter_house function coded like this:


function enter_house($house, $door, $pocket) {
    $key = find_key($pocket);
    $door = open_door($door, $key);
    if ($door == 'open') {
        $house = 'full';
    }
    return $house;
}

while the function still does the same this is... less functional, because you create temporary variables when not really needed and may omit introducing functions thus spoiling decomposition.

You may still have temporary variables when needed, but in a more functional kind of way, like “values binding”:


/*
 * Imagine, we need to open two doors with the same key in order to enter the house
 */
function enter_house($house, $door1, $door2, $pocket) {
    return
        // When BOTH (&&) doors are opened with the $key found
        open_door($door1, $key = find_key($pocket)) == 'open' && open_door($door2, $key)
            // we enter the house
            ? 'full'
            : $house;
}

Some mutable data here, but looks and feels like immutable. That’s something.

Of course this is nothing more than a fun trick to get you thinking in the right direction. Any time you have real problems - use all the power of PHP and create your variables away. =D

First-class functions and Higher Order functions

Wikipedia says that PHP does have First-class functions since the 5.3 version with the exception of partial application and nested functions. They obviously refer to the Closures added. However due to dynamic nature of PHP you could use other types as if they were functions, even before PHP5.3:

/* callable string */

function hello($name) {
    return 'Hello ' . $name;
}

$func = 'hello';
echo is_callable($func) ? 'Yes' : 'No'; // echoes "Yes"
echo $func('John'); // echoes 'Hello John'

/* callable array */

class Helloer {
    public function hello($name) {
        return 'Hello ' . $name;
    }
}

$func = array(new Helloer, 'hello');
echo is_callable($func) ? 'Yes' : 'No'; // echoes 'Yes'
echo call_user_func($func, 'Alex'); // echoes 'Hello Alex'
// Note: with PHP5.4 you can already do this: $func('Alex') even for array-callables

/* callable anonymous function */

$func = function($name) { return 'Hello ' . $name; };
echo is_callable($func) ? 'Yes' : 'No'; // echoes 'Yes';
echo $func('Peter'); // echoes 'Hello Peter'


There is this pseudo-type: “callable” and as of PHP5.4 you are able type hint on it. (https://wiki.php.net/rfc/callable). In prior versions you just need to know that callable may be a string, an array or a closure. Of course you can pass/return strings, arrays and closures to/from functions so here you have the higher order functions:

/*
 * You realize that there may be many ways to open a door and you are not sure
 * which one you'll need when. So you add another parameter to the enter_house function
 * which means "How do we open the door".
 *
 * We can even specify the default value, which PHP allows us, to provide backwards compatibility
 */
function enter_house($house, $door, $pocket, $doorOpener = 'open_door') {
    return
        $doorOpener($door, find_key($pocket))
            == 'open'
                ? 'full'
                : $house;
}

// ... but in case we forgot our keys at work and we really need to get in, we can provide an alternative way
// of opening the door:
function break_in() {
    // for instance, we can open the door with our leg,
    // in this case we don't need a key :)
    return 'open';
}

echo
    enter_house(
        $house,
        $door,
        $pocket,
        'break_in' // this is it, we specify how we want to open the door
    );


Closures and anonymous functions

Anonymous functions are those without a name. We have them as Closures since PHP5.3 (and before that we could create anonymous functions via create_function).

Usually useful for some things small when it’s really not worth it to create a real function:

/*
 * Remember the break_in example? The break_in function was so small and simple it hardly needed a name
 * Here is how we could do the same using an anonymous function:
 */
echo
    enter_house(
        $house,
        $door,
        $pocket,
//        'break_in'
        function() { return 'open'; }
    );


Closures are a much more powerful toy through which you can simulate some of the functional programming languages features - you’ll see more on that later. For now, let’s just say that we have closures in PHP and in order to create a reference to an outer scope variable you gotta use the “use” keyword:

// Modifying the break_in example to use a Closure

$axe = 'Metal Axe';
$breakInWithAnAxe = function($door) use ($axe) {
    /* ... smashing the door with an $axe from the outer scope here ...*/
};

echo
    enter_house(
        $house,
        $door,
        $pocket,
        $breakInWithAnAxe
    );


I’ll give a couple more closure usage examples later.

Recursion

An old friend of yours isn’t it? If not - fix that right away! I couldn’t have put it better than in wiki:

Recursion in computer science is a method where the solution to a problem depends on solutions to smaller instances of the same problem.

This is all for the sake of avoiding state and mutable data. Here is an example of pick_the_right_key function implementation for the case when we don’t know it’s indexed by “housekey”. For instance it could be a situation when we don’t know the key’s color but we remember it has a tiny label on it and we need to check all keys in order to find it.

/*
 * Implementation with a loop.
 */
function pick_the_right_key($keys) {
    // we are thinking imperative again, using "Steps".
    // Even though the steps are all the same:
    while($key = array_shift($keys)) { // take one key
        if ($key == 'Home Sweet Home') { // check if that's the one
            return $key;                // the key is found
        }
    }
}
/*
 * Implementation with a recursion
 */
function pick_the_right_key($keys) {
    return
        // checking the first key in the set
        ($key = array_shift($keys)) == 'Home Sweet Home'
             // return if that's what we need
             ? $key
             // otherwise we pick the right key in what is left of the keys!
             : pick_the_right_key($keys); // Note: array_shift `removes` the first element of the array,
                                          // so at this point $keys is a new value
                                          // that does not contain the $key we already checked
}


In case with the recursion code we don’t have consecutive instructions: we express our needs through calls of other functions. Even if it’s the same function we are in at the moment.

Partial Application and Currying

Partial Application and Currying are actually different things. I’m going to speak about partial application: a way to get a new function by partially applying another one.

Say, you have a function like this:

// The function that calculates the sum of these four
function add($a, $b, $c, $d) {
    return $a + $b + $c + $d;
}


and at some point you realize that you need another one in a few places. One that does the same but the value of $a is fixed so you create something like this:

// the new function could look like this:
$myAdd = function ($b, $c, $d) {
    return add(10, $b, $c, $d);
};

// or this:
function my_new_add($c, $d) {
    return add(1, 2, $c, $d);
}


Normally, in PHP you could just create another function embracing a call to the original function. But if you get on well with the functional way of thinking you may need to dynamically create functions based on existing ones for your particular local needs.

I have a special curry function (which I actually use for some things), that makes it possible to create these functions on the fly. Here is the function and how you can use it:

// with partial application, you can do this instead:
$myAdd = curry('add', 10);
$myNewAdd = curry('add', 1, 2);
// or even this
$superAdd = curry($myNewAdd, 2); // so this $superAdd here has $a, $b, $c "partially applied"

echo $superAdd(2);

function curry() {
    $params = func_get_args();
    $function = array_shift($params);
    return function() use ($function, $params) {
        return call_user_func_array($function,
                                    array_merge($params, func_get_args()));
    };
}


Free-point style and functions composition

This is similar to currying from some point of view as it allows you to get a function you need for a particular local need that composes a few other functions without having to explicitly define it.

Here is what you would normally do in PHP:

function sum($a, $b, $c) {
    return $a + $b + $c;
}

function make_two($a) {
    return $a * 2;
}

function add_three($a) {
    return $a + 3;
}


// you need to create new function like this
function double_sum($a, $b, $c) {
    return make_two(sum($a, $b, $c));
}

// or like this
function my_add($a, $b, $c) { // we are listing the arguments here
    return add_three(
        make_two(
            add_three(
                sum($a, $b, $c) // and here again
            )
        )
    );
}

And here is a function that does this on the fly and a usage example:

$doubleSum = compose('make_two', 'sum');
$myAdd = compose('add_three', 'make_two', 'add_three', 'sum'); // no mention of arguments in this case

function compose() {
    $functions = array_reverse(func_get_args());
    return function() use($functions) {
        $params = func_get_args();
        return array_reduce($functions,
            function($result, $next) use ($params) {
                        return $result === null
                            ? call_user_func_array($next, $params)
                            : $next($result);
                    }
        );
    };
}


While you may not start using any of these tricks right away, the idea to keep in mind is that with closures you can imitate many of the functional languages features.

Afterword

The list is not full of course. I just thought these were interesting. Don’t forget the main point - the functional approach to solving problems is about the way you think.

Please, leave comments and let me know if you succeed applying any of these techniques/tricks in your projects.