Functional Programming in PHP: Part 3
Now that we have covered referential transparency, a concept fundamental to functional programming, I can introduce helper functions and value objects. Helper functions provide exactly that, help. Imagine a situation which might require you to pass parameters to a function one by one lazily; imperative programming might not suffice as you might get an error. Enter currying, an approach whose usefulness lies in its convenience. An implementation of the currying principle exists in the bingo-functional library available for download via Composer.
composer require chemem/bingo-functional
The curry function in the library enables one to successfully curry a function — pass arguments to a desired function one by one. Closely related to currying is partial application which is only subtly different from its relative. This difference is in arity. Implicit in the definition of currying is the creation of a new function for each argument passed. Partial application, simply put, is an operation whose implementation can depict a variable arity.
use Chemem\Bingo\Functional\Algorithms as A;function add(int $a, int $b, int $c) : int
return $a + $b + $c;
}$curryAdd = A\curry('add');$partialAdd = A\partialLeft('add', 12);$curryAddFirst = $curryAdd(12); //arity = 1$curryAddSecond = $curryAdd(13); //arity = 1, again$curryAddThird = $curryAdd(14); //you get it, right?$partialAddValues = $partialAdd(13, 14); //arity = 2
Currying and partial application are not the only helpers worth noting. Composition, yet another fundamental concept is one worthy of conversation. Composing functions, simply put, is combining functions. As is the case with Mathematics, combining f(x) and g(x) yields one function f(g(x)). Programmatically, functions f and g could be any function whose parameters are known. Composing functions programmatically in the manner compose(‘f’, ‘g’) is said to follow a point-free style.
function plusTen(int $a) : int
return $a + 10;
}function multiplyByFive(int $b) : int
return $b * 5;
}$composedOp = A\compose('plusTen', 'multiplyByFive');$composeRes = array_map($composedOp, [1, 2, 3, 4]);
//should yield [55, 60, 65, 70]
Following the rhetoric of a sage programmer, if you are chaining, you are composing. Composing functions is therefore ubiquitous and performed almost inadvertently a lot. A point-free composition of functions has clear outcomes: I find that this approach makes it easy to determine the direction of logic. As depicted in the snippet above, adding ten to each value and multiplying by five are operations with explicit, tacit outcomes.
Composition, currying, and partial application are not the only helper functions in existence; zip(), unzip(), and isArrayOf() helpers are other morphisms worth exploring. Onto value objects now, the subject of a previous article of mine. A value object is an immutable object which represents an entity: when compared to another value object, it is only similar to it in value and not in identity.
private $msg; //text to be conveyed private $response; //a response code public function __construct($msg, $response)
$this->msg = $msg;
$this->response = $response;
} public function getMessage()
} public function verify(Message $m) : bool
return $this->msg == $m->msg &&
$this->response == $m->response; //equational reasoning
} public function newMsg($msg, $response) : Message
$newMsg = clone $this;
$new->msg = $msg;
$new->response = $response;
}$clearMsg = new Message('Functional programming is hard', 200);$newMsg = $clearMsg->newMsg('Functional programming is cool', 200);var_dump($newMsg->verify($clearMsg)); //should return false
The example shown above demonstrates this immutability. The value object $clearMsg has a different value from that of the value object $newMsg. Also, notice the use of equational reasoning to make the comparison between objects as well as the absence of setters. I do not recommend the use of the triple equals, ‘===’ when comparing objects because PHP will compare the objects and not the values. Since the language does not support immutable classes which would otherwise make the computation of immutable, distinct objects a breeze, value objects should suffice to this end.
To create a value object, fashion a class to exhibit the following traits: the absence of setters besides a constructor akin to a one-time setter and the presence of private attributes whose values change only on context cloning as well as methods to help manipulate class context.
In conclusion, I hope that you use the PHP Read Evaluate Print Loop (REPL) utility to test the sample code as it makes for a nice code sandbox. In the next installment of the series, I will elucidate collection transformation functions array_map(), array_reduce(), and array_filter().
The series — Functional Programming in PHP — is now a book. The volume eponymous with the blog content is currently available on Leanpub.