Real-Life Monads - Functional PHP (2017)

Functional PHP (2017)

Chapter 6. Real-Life Monads

In the previous chapter, we covered a lot of theoretical ground concerning various abstractions, leading us to the concept of monads. It is now time to apply this knowledge by presenting a few instances of monads that will prove useful in your day-to-day coding.

Each part will start with an introduction to the issue solved by the given monad, followed by some examples of usage so that you can gain some practice. As explained at the end of this introduction, the implementation itself won't be present in the book to concentrate on usage.

As you will see, once you get the theory out of the way, most implementation will seem pretty natural to you. Also, the usefulness extends beyond the realm of functional programming. Most of what we will learn in this chapter can be applied in any development context.

Most of the monads that will be presented relate to the management of side effects, or rather affects once they are explicitly contained inside a Monad. When doing functional programming, a side effect is unwanted. Once contained, we can control them so that they are merely effects of our program.

Monads are used for mainly two reasons. The first is that they are great to perform flow control, as already explained in the last chapter. The second is that their structure allows you to easily encapsulate effects and protect the rest of your code from the impurity.

However, let's keep in mind that this is only one of the possible uses of a monad. You can do much more with the concept. But let's not get ahead of ourselves; we will discover that along the way.

In this chapter, we will cover the following topics:

· Monadic helper methods

· The Maybe and Either monads

· The List monad

· The Writer monad

· The Reader monad

· The State monad

· The IO monad

In order to concentrate on using monads, and since the implementation is often not the most important part, we will use the ones provided by the PHP Functional library. Obviously, important implementation details will be highlighted in the book. You can install it in your project using the composer invocation:

composer require widmogrod/php-functional

It is important to note that the php-functional library's author made some other choices concerning the naming of the methods and some implementation details:

· The apply method is simply ap

· The unit and return keywords are replaced by of in the class

· The inheritance tree is a bit different, for example, there are Pointed and Chain interfaces

· The library uses traits for shared code

· Some helper functions are implemented outside of the class and need to be imported separately

Monadic helper methods

In the previous chapter, we spoke about the flatten method and how it can be used to compress multiple nested levels of the same monad instance. This function is often spoken about because it can be used to rewrite the monad in another light. There are, however, other helpful helpers.

The filterM method

Filtering is a key concept in functional programming, but what if our filter functions return a monad instead of a simple Boolean value? This is what the filterM method is for. Instead of expecting a predicate that returns a simple Boolean value, the filterM method will use any predicate that can be converted to a Boolean and also wrap the resulting collection in the same monad:

<?php

use function Functional\head;

use function Functional\tail;

use Monad\Writer;

function filterM(callable $f, $collection)

{

$monad = $f(head($collection));

$_filterM = function($collection) use($monad, $f, &$_filterM){

if(count($collection) == 0) {

return $monad->of([]);

}

$x = head($collection);

$xs = tail($collection);

return $f($x)->bind(function($bool) use($x, $xs, $monad, $_filterM) {

return $_filterM($xs)->bind(function(array $acc) use($bool, $x, $monad) {

if($bool) {

array_unshift($acc, $x);

}

return $monad->of($acc);

});

});

};

return $_filterM($collection);

}

The implementation is a bit hard to follow, so I'll try to explain what is going on:

1. First, we need to have the information about the monad we are working with, so we extract the first element of our collection and get the monad from it by applying the callback.

2. We then declare a closure around the monad and the predicate.

3. The closure first tests whether the collection is empty. If this is the case, we return an instance of the monad containing an empty array. Otherwise, we run the predicate on the first element of the collection.

4. We bind a closure holding the current value to the resulting monad containing a Boolean.

5. The second closure recursively traverses the whole array, if needed.

6. Once we are on the last element, we bind a new closure that will use the Boolean to add the value to the accumulator or not.

This is not easy stuff, but as it is mostly internal plumbing, made more difficult by PHP's lack of syntactic sugar, understanding everything is not necessary at all. For comparison, here is the same code implemented using Haskell pattern matching and do notation features:

filterM :: (Monad m) => (a -> m Bool) -> [a] -> m [a]

filterM _ [] = return []

filterM f (x:xs) = do

bool <- f x

acc <- filterM p xs

return (if bool then x:acc else acc)

As you can see, this is a bit easier to read. I think anyone would be able to understand what is going on. Unfortunately, in PHP, we have to create nested inner functions to achieve the same results. This is, however, not really a concern, since the resulting function is fairly easy to use. The inner working of some functional patterns might, however, sometimes a bit gruesome in PHP and not perfectly functional themselves.

Examples will follow as we discover some monads. An implementation of this helper is available in the php-functional library.

The foldM method

The foldM method is the monadic version of the fold method. It takes a function that returns a monad and then produces a value that is also a monad. The accumulators and collection are, however, simple values:

<?php

function foldM(callable $f, $initial, $collection)

{

$monad = $f($initial, head($collection));

$_foldM = function($acc, $collection) use($monad, $f, &$_foldM){

if(count($collection) == 0) {

return $monad->of($acc);

}

$x = head($collection);

$xs = tail($collection);

return $f($acc, $x)->bind(function($result) use($acc,$xs,$_foldM) {

return $_foldM($result, $xs);

});

};

return $_foldM($initial, $collection);

}

The implementation is a tad smaller than the one for the filterM method because we only need to recurse; no transformation from Boolean to the value needs to happen. Again, we will show a few examples in the following parts of the chapter and an implementation is also available in the php-funcational library.

Closing words

There exist multiple other functions that can be enhanced to be used with monadic values. For example, you can have the zipWithM method, which merges two collections using a merge function returning a monad. The php-functional library has an implementation of mcompose which allows you to compose functions returning the same monad instance.

When you discover some kind of recurring pattern when you are using monads, don't hesitate to factor it into a helper function. It will probably come in handy more often than not.

Maybe and Either monads

You should already be well aware of the Maybe and Either types we have discussed multiple times already. We first defined them, then we learned that they are in fact perfect examples of a functor.

We will now go even further and define them as monads, so we will be able to use them in even more situations.

Motivation

The Maybe monad represents the idea that a sequence of computation can, at anytime, stop returning a meaningful value using the Nothing class we defined in an earlier chapter. It's particularly useful when chain of transformations depend on one another and where some step may fail to return a value. It allows us to avoid the dreaded null checks that often come with such a situation.

The Either monad has mostly the same motivation. The slight difference is that the steps usually either throw an exception or return an error instead of an empty value. The fact that the operation fails entails that we need to store an error message symbolized by the Left value instead of the Nothing value.

Implementation

The code for both Maybe and Either types can be found in php-functional library. The implementation is pretty straightforward-the major difference from our own previous implementation is that methods such as isJust and isNothing are missing, and that instances are constructed using helper functions instead of static factories.

It is important to note that the Either monad as implemented in php-functional library sadly does not take care of catching exceptions itself. The functions you are either applying or binding to it must take care to do so correctly themselves. You can also use the tryCatch helper function to do so for you.

Examples

To get a better grasp of how Maybe monad works, let's have a look at a few examples. php-functional library uses helper functions instead of static methods on the class to create new instances. They live in the Widmogrod\Monad\Maybe namespace.

Another really useful helper is the maybe method, which is a curryied with the following signature-the maybe($default, callable $fn, Maybe $maybe) namespace. When called, it will first try to extract the value from $maybe variable, defaulting to a $default variable. It will then be passed as a parameter to $fn variable:

<?php

use Widmogrod\Monad\Maybe as m;

use Widmogrod\Functional as f;

$just = m\just(10);

$nothing = m\nothing();

$just = m\maybeNull(10);

$nothing = m\maybeNull(null);

echo maybe('Hello.', 'strtoupper', m\maybe('Hi!'));

// HI!

echo maybe('Hello.', 'strtoupper', m\nothing());

// HELLO.

Now that the helpers are out of the way, we will demonstrate how Maybe monad can be used in combination with the foldM method:

<?php

$divide = function($acc, $i) {

return $i == 0 ? nothing() : just($acc / $i);

};

var_dump(f\foldM($divide, 100, [2, 5, 2])->extract());

// int(5)

var_dump(f\foldM($divide, 100, [2, 0, 2])->extract());

// NULL

Implementing this using a traditional function and the array_reduce method would mostly result in something really similar, but it demonstrates nicely how the foldM method works. Since the folding function is bound to the current monadic value on each iteration, as soon as we have a null value, the following steps will just continue returning nothing until the end. The same function could be used to return some other kind of monad to also hold information about the failure.

We already saw before how the monad type can be used to chain multiple functions together on a value that may or may not exist. However, if we need to use this value to get another value that could be nothing, we will have nested Maybe instances:

<?php

function getUser($username): Maybe {

return $username == 'john.doe' ? just('John Doe') : nothing();

}

var_dump(just('john.doe')->map('getUser'));

// object(Monad\Maybe\Just)#7 (1) {

// ["value":protected]=> object(Monad\Maybe\Just)#6 (1) {

// ["value":protected]=> string(8) "John Doe"

// }

// }

var_dump(just('jane.doe')->map('getUser'));

// object(Monad\Maybe\Just)#8 (1) {

// ["value":protected]=> object(Monad\Maybe\Nothing)#6 (0) { }

// }

In this case, you could use the flatten method, or simply the bind method instead of the map method:

<?php

var_dump(just('john.doe')->bind('getUser'));

// object(Monad\Maybe\Just)#6 (1) {

// ["value":protected]=> string(8) "John Doe"

// }

var_dump(just('jane.doe')->bind('getUser'));

// object(Monad\Maybe\Nothing)#8 (0) { }

I agree that the examples for Maybe monad are a bit anticlimactic as most of the uses were already described earlier monads are only a pattern, thus creating a Maybe monad does not add feature in itself, it will only allow us with other patterns expecting a monad; the features stay the same as before.

A similar case can be made for Either monad; this is why there won't be any new examples for it here. Just make sure to have a look at the helper functions instead of rewriting the plumbing yourself when you want to use the monad.

List monad

The List or Collection monad represents the category of all functions taking a collection as a parameter and returning zero, one, or several values. The function is applied to all possible values in the input list and the results are concatenated to product a new collection.

An important thing to understand is that a list monad does not really represent a simple list of values, but rather a list of all different possible values for the monad. This idea is often described a non-determinism. As we saw with the CollectionApplicative function, this can lead to interesting results when you apply a collection of functions with a collection of values. We will try to expand on this topic in the examples to clarify this.

Motivation

The List monad embodies the idea that you cannot know the best result until the end of the full computation. It allows us to explore all possible solutions until we have a final one.

Implementation

The monad is implemented in the php-functional library under the name the Collection method. It is done in a pretty straightforward way. Two new methods are, however, available in comparison to our own previous implementation:

· The reduce method will perform a fold operation on the values stored inside the monad.

· The traverse method will map a function returning an applicative to all values stored inside the monad. The applicative is then applied to the current accumulator.

Examples

Let's start with something hard, using the filterM method that we previously discovered. We will create something that is called the powerset of a set. The powerset collection is all possible subsets of a given set, or, if you like, all possible combination of its members:

<?php

use Monad\Collection;

use Functional as f;

$powerset = filterM(function($x) {

return Collection::of([true, false]);

}, [1, 2, 3]);

print_r($powerset->extract());

// Array (

// [0] => Array ( [0] => 1 [1] => 2 [2] => 3 )

// [1] => Array ( [0] => 1 [1] => 2 )

// [2] => Array ( [0] => 1 [1] => 3 )

// [3] => Array ( [0] => 1 )

// [4] => Array ( [0] => 2 [1] => 3 )

// [5] => Array ( [0] => 2 )

// [6] => Array ( [0] => 3 )

// [7] => Array ( ) // )

Note

This currently doesn't work with the actual implementation of Collection/filterM due to the fact that the constructor does not wrap an actual array inside another. See https://github.com/widmogrod/php-functional/issues/31.

What is happening here? It may seem as if it is some kind of dark magic. In fact, it is pretty simple to explain. Binding a function to a collection results in this function being applied to all its members. In this particular case, our filtering function returns a collection containing both true and false values. This means the inner closure of the filterM method responsible for replacing the Boolean with the value is run twice and the result is then appended to all previously created collections. Let's see the first steps to make things clearer:

1. The filter is first applied to the value 1, creating two collections [] and [1].

2. The filter is now applied to the value 2, creating two new collections ([] and [2]) that need to be appended to the ones we created earlier, creating four collections [], [1], [2], [1, 2].

3. Each new step creates two collections that are appended to the previous ones, making the number of collections grow exponentially.

Still not clear? Let's look at another example. This time, try imagining the collection as a tree where each initial value is a branch. When you bind a function, it is applied to each branch and, if the result is another collection, it creates new branches:

<?php

use Monad\Collection;

use Functional as f;

$a = Collection::of([1, 2, 3])->bind(function($x) {

return [$x, -$x];

});

print_r($a->extract());

// Array (

// [0] => 1

// [1] => -1

// [2] => 2

// [3] => -2

// [4] => 3

// [5] => -3

// )

$b = $a->bind(function($y) {

return $y > 0 ? [$y * 2, $y / 2] : $y;

});

print_r($b->extract());

// Array (

// [0] => 2

// [1] => 0.5

// [2] => -1

// [3] => 4

// [4] => 1

// [5] => -2

// [6] => 6

// [7] => 1.5

// [8] => -3

// )

In order to make matters a bit more complicated for you, the second function returns a variable number of elements based on the given value. Let's visualize this as a tree:

Examples

Where can the knight go?

Now that we have a good understanding of how the Collection monad works, let's tackle a more difficult challenge. Given a starting position on a chessboard, we want to know all possible valid positions a knight piece can reach in three moves.

I want you to take a moment to imagine how you would implement that. Once you are done, let's try using our monad. We first need a way to encode our knight position. A simple class will suffice. Also, a chessboard has eight columns and eight rows, so let's add a method to check whether the position is valid:

<?php

class ChessPosition {

public $col;

public $row;

public function __construct($c, $r)

{

$this->col = $c;

$this->row = $r;

}

public function isValid(): bool

{

return ($this->col > 0 && $this->col < 9) &&

($this->row > 0 && $this->row < 9);

}

}

function chess_pos($c, $r) { return new ChessPosition($c, $r); }

Now we need a function that returns all valid moves for a knight, given a starting position:

<?php

function moveKnight(ChessPosition $pos): Collection

{

return Collection::of(f\filter(f\invoke('isValid'), Collection::of([

chess_pos($pos->col + 2, $pos->row - 1),

chess_pos($pos->col + 2, $pos->row + 1),

chess_pos($pos->col - 2, $pos->row - 1),

chess_pos($pos->col - 2, $pos->row + 1),

chess_pos($pos->col + 1, $pos->row - 2),

chess_pos($pos->col + 1, $pos->row + 2),

chess_pos($pos->col - 1, $pos->row - 2),

chess_pos($pos->col - 1, $pos->row + 2),

])));

}

print_r(moveKnight(chess_pos(8,1))->extract());

// Array (

// [0] => ChessPosition Object ( [row] => 2 [col] => 6 )

// [1] => ChessPosition Object ( [row] => 3 [col] => 7 )

// )

Nice, it seems to be working well. Now all we need to do is bind this function three times in a row. And, while we are at it, we will also create a function that checks whether a knight can reach a given position in three steps:

<?php

function moveKnight3($start): array

{

return Collection::of($start)

->bind('moveKnight')

->bind('moveKnight')

->bind('moveKnight')

->extract();

}

function canReach($start, $end): bool

{

return in_array($end, moveKnight3($start));

}

var_dump(canReach(chess_pos(6, 2), chess_pos(6, 1)));

// bool(true)

var_dump(canReach(chess_pos(6, 2), chess_pos(7, 3)));

// bool(false)

The only thing left to do is to check on a real chessboard whether our functions work correctly. I don't know how you imagined doing this in an imperative way, but my own solution for once was a lot less elegant than the one we've got here.

If you want to play a bit more, you can try to parametrize the number of moves or implement this for other chess pieces. As you will see, it requires only minimal changes.

Writer monad

If you remember, pure functions cannot have any side effects, meaning you cannot put a debug statement in them, for example. If you are like me, the var_dump method is your debugging tool of choice, so you are left with breaking your purity rule or using some other debugging techniques. Since all outputs of a function must go through its return value, one of the first ideas that comes to mind is to return a tuple of values-the original return value and any kind of debug statement you need.

This solution is, however, pretty complex to put in place. Imagine you have a function that halves a numerical value which returns the halved value and the received input for debugging purposes. Now, if you want to compose this function by itself to create a new function that returns the value divided by four, you also need to modify the inputs so that they can accept your new return format. And this goes on and on until you've modified all your functions accordingly. This also poses some issues with currying, as you now have an extraneous parameter which is not really useful if you don't care about the debug statements.

The solution you are looking for is the Writer monad. Sadly, there are no implementations in php-functional library at the time of writing.

Motivation

The Writer monad is used to encapsulate some kind of associated statement alongside the principal return value of a function. This statement can be anything. It is often used to store generated debugging output or tracing information. Doing so manually is cumbersome and can lead to complex management code.

The Writer monad provides a clean way to manage such side output and allows you to interleave functions returning such information alongside functions returning simple values. At the end of the computation sequence, the supplementary values can be either discarded, displayed, or treated in any kind of way depending on the mode of operation.

Implementation

Since the monad needs to concatenate the output values, any instance of a monoid can be used as such. To simplify string-based logging, any string is also managed out-of-the-box. Obviously, using a monoid with a slow operation will result in a performance cost.

The php-functional library includes an implementation of a StringMonoid class to which each string will be lifted. However, the runWriter method will always return a StringMonoid class, so there is no surprise for people using it. Besides that, the implementation is pretty straightforward.

Examples

As we just saw, the Writer is great for logging. Coupled with the filter method, this can be leveraged to understand what is happening in a filtering function without having to resort to dumping values:

<?php

$data = [1, 10, 15, 20, 25];

$filter = function($i) {

if ($i % 2 == 1) {

return new Writer(false, "Reject odd number $i.\n");

} else if($i > 15) {

return new Writer(false, "Reject $i because it is bigger than 15\n");

}

return new Writer(true);

};

list($result, $log) = filterM($filter, $data)->runWriter();

var_dump($result);

// array(1) {

// [0]=> int(10)

// }

echo $log->get();

// Reject odd number 1.

// Reject odd number 15.

// Reject 20 because it is bigger than 15

// Reject odd number 25.

As we can see, Writer monad allows us to have exact information about why certain numbers were filtered out. It may seem like nothing in such a simple example, but conditions are not always as easy to understand.

You can also use Writer to add more traditional debug information:

<?php

function some_complex_function(int $input)

{

$msg = new StringMonoid('received: '.print_r($input, true).'.');

if($input > 10) {

$w = new Writer($input / 2, $msg->concat(new StringMonoid("Halved the value. ")));

} else {

$w = new Writer($input, $msg);

}

if($input > 20)

{

return $w->bind('some_complex_function');

}

return $w;

}

list($value, $log) = (new Writer(15))->bind('some_complex_function')->runWriter();

echo $log->get();

// received: 15. Halved the value.

list($value, $log) = some_complex_function(27)->runWriter();

echo $log->get(); // received: 27. Halved the value. received: 13. Halved the value.

list($value, $log) = some_complex_function(50)->runWriter();

echo $log->get();

// received: 50. Halved the value. received: 25. Halved the value. received: 12. Halved the value.

This monad is great keeping track of useful information. Also, it often avoids leaving some unwanted var_dump or echo methods in your function and library code. Once you are done debugging, leave the messages there-they might prove useful to someone else, and just remove the use of the $log value returned by the runWriter method.

Obviously, you can also use Writer monad to keep track of any kind of information. One good use could be to back profiling right into your function by always returning the execution time via a Writer instance.

If you need to store multiple kinds of data, the Writer monad is not limited to string values, any monoid will do. You can, for example, declare a specific monoid containing execution time, stack trace, and debug messages in an array and use that with your Writer. This way, each of your functions will be able to pass useful information to anyone calling them.

We could argue that it slows your program down always having that kind of information. This is probably correct, but I'd imagine that those kind of optimizations are not needed in most applications.

Reader monad

It so happens that you have a bunch of functions that should all take the same parameter, or a subset of a given list of values. For example, you have a configuration file and various parts of your application need to have access to values stored in it. One solution is to have some kind of global object or singleton to store that information, but as we already discussed, this leads to some issues. A more common approach in modern PHP frameworks is to use a concept called Dependency Injection (DI). The Reader monad allows you to do exactly that in a purely functional way.

Motivation

Provide a way to share a common environment, such as configuration information or class instances, across multiple functions. This environment is read-only for the computation sequence. However, it can be modified or extended for any sub-computation local to the current step.

Implementation

The Reader class performs function evaluation lazily because the content of the environment is not yet known when the function is bound. This means all functions are wrapped inside closures inside the monad and everything is run when the runReader method is called. Besides that, the implementation available in php-functional library is pretty straightforward.

Examples

Using the Reader monad is a bit different than what we have seen until now. The bound function will receive the value from the previous step in the computation and must return a new reader that holds a function receiving the environment. If you just want to process the current value, it is easier to use the map function, as it does not require a Reader instance to be returned. You will, however, not receive the context:

<?php

function hello()

{

return Reader::of(function($name) {

return "Hello $name!";

});

}

function ask($content)

{

return Reader::of(function($name) use($content) {

return $content.

($name == 'World' ? '' : ' How are you ?');

});

}

$r = hello()

->bind('ask')

->map('strtoupper');

echo $r->runReader('World');

// HELLO WORLD!

echo $r->runReader('Gilles');

// HELLO GILLES! HOW ARE YOU ?

This not-so-interesting example just poses the basics of what you can do. The next example will show how you can perform DI using this monad.

Note

If you've used a modern web framework, you probably already know what dependency injection, or DI, is. Otherwise, here is a real quick explanation, for which I could probably get burned at the stake. DI is a pattern to avoid using singletons or globally available instances. Instead, you declare your dependencies as functions or constructor parameters and a Dependency Injection Container (DIC) is tasked with providing them to you.

Usually, this involves letting the DIC instantiate all your objects instead of using the new keyword, but the method varies from one framework to another.

How do we do that using the Reader monad? It's pretty simple. We need to create a container that will hold all our services and then we will use our reader to pass those around.

For the sake of the example, let's say we have an EntityManager for our users that connects to the database and a service to send e-mails. Also, to keep things simple, we won't do any encapsulation, and we will use simple functions instead of classes:

<?php

class DIC

{

public $userEntityManager;

public $emailService;

}

function getUser(string $username)

{

return Reader::of(function(DIC $dic) use($username) {

return $dic->userEntityManager->getUser($username);

});

}

function getUserEmail($username)

{

return getUser($username)->map(function($user) {

return $user->email;

});

}

function sendEmail($title, $content, $email)

{

return Reader::of(function(DIC $dic) use($title, $content, $email) {

return $dic->emailService->send($title, $content, $email);

});

}

Now we want to write the controller that gets called after a user registers on our application. We will need to send them an e-mail and display some kind of confirmation. For now, let's assume the user is already saved in the database and that our theoretical framework provides the use of the POST method values as a parameter:

<?php

function controller(array $post)

{

return Reader::of(function(DIC $dic) use($post) {

getUserEmail($post['username'])

->bind(f\curry('sendEmail', ['Welcome', '...']))

->runReader($dic);

return "<h1>Welcome !</h1>";

});

}

OK, we have everything in place for a quick test. We will create some face service classes to see whether the plumbing works correctly:

<?php

$dic = new DIC();

$dic->userEntityManager = new class() {

public function getUser() {

return new class() {

public $email = 'john.doe@email.com';

};

}

};

$dic->emailService = new class() {

public function send($title, $content, $email) {

echo "Sending '$title' to $email";

}

};

$content = controller(['username' => 'john.doe'])->runReader($dic);

// Sending 'Welcome' to john.doe@email.com

echo $content;

// <h1>Welcome !</h1>

Obviously, we don't have a usable framework yet, but I think this demonstrates nicely the possibilities offered by the Reader monad when it comes to DI.

Concerning the IO operations that need to be done to store the newly created user in the database and the mail sending, we will see how it can be achieved using the IO monad that we will present later.

State monad

The State monad is a generalization of the reader monad in the sense that each step can modify the current state before the next step is called. As a referentially transparent language cannot have a shared global state, the trick is to encapsulate the state inside the monad and pass it explicitly to each part of the sequence.

Motivation

It provides a clean and easy-to-use process to pass a shared state across multiple steps in a sequence. This can obviously be done manually but the process is error prone and leads to less readable code. The monad hides the complexity so that you can simply write functions taking a state as input and returning a new state.

Implementation

The implementation available in the php-functional library is nearly identical to the one we just discussed for the Reader monad, with just one key difference-the state can be updated by each bound function. This leads to a difference in the functions that are bound to the monad-instead of returning a value, they need to return an array containing the value as first element and the new state as second element.

Examples

As we already discussed, it is impossible for a function to return the current time or some kind of random value. The state monad can help us do exactly this by providing a clean way to pass the state variable around, exactly as we did with our Reader environments earlier:

function randomInt()

{

return s\state(function($state) {

mt_srand($state);

return [mt_rand(), mt_rand()];

});

}

echo s\evalState(randomInt(), 12345);

// 162946439

Another use of the state monad is to implement a caching system:

<?php

function getUser($id, $current = [])

{

return f\curryN(2, function($id, $current) {

return s\state(function($cache) use ($id, $current) {

if(! isset($cache[$id])) {

$cache[$id] = "user #$id";

}

return [f\append($current, $cache[$id]), $cache];

});

})(...func_get_args());

}

list($users, $cache) = s\runState(

getUser(1, [])

->bind(getUser(2))

->bind(getUser(1))

->bind(getUser(3)),

[]

);

print_r($users);

// Array (

// [0] => user #1

// [1] => user #2

// [2] => user #1

// [3] => user #3

// )

print_r($cache);

// Array (

// [1] => user #1

// [2] => user #2

// [3] => user #3

// )

As we can see, the user list contains the user 1 two times, but the cache only once. This is a pretty basic cache mechanism, but it can come in handy.

There are many other uses for the state monad, but to be honest, without syntactic sugar like the do notation and such, I am not quite sure it is a good fit for PHP programming. If you are interested, I am sure you will find many other resources online but we will stop there with the examples.

IO monad

Inputs and outputs are the quintessence of side effects. There is no way to guarantee purity when you get your function output from an external source as those change without relation to the inputs. And as soon as you output something, be it to the screen, a file, or anywhere else, you changed an external state unrelated to your function outputs.

Some people in the functional community argue that, for example, logging outputs or debugging statements should not necessarily be considered as side-effects as usually they have no consequences on the outcome of running your application. The end user doesn't care whether something was written to a log file or not as long as it gets the wanted result back and the operation is repeatable at will. Truthfully, my opinion on the subject is not quite made, and honestly I don't really care as the writer monad lets us take care of logging and debugging statements in a clever way.

However, there are some times when you need to have information from the outside and usually, if your application is doing anything worthy, you need to display or write the final result somewhere.

We could imagine getting all values before beginning any computation and passing them around using some kind of clever data structure. This could work for some simpler applications, but as soon as you need to perform database access based on some computed values, reality starts to set in and you realize that this isn't at all viable in the long term.

The trick proposed by the IO monad is to do what we just proposed but in reverse. You start by describing all computational steps needed by your program. You encapsulate them in an instance of the IO monad and when everything is cleanly defined in terms of referentially transparent function calls, you start the beast which will finally perform all needed IO actions, and call each described step.

This way, you have an application composed only of pure functions, which you can easily test and understand. All actions related to inputs and outputs are performed at the end, the complexity being hidden inside the IO monad. In order to enforce this, the IO monad is said to be a one-way monad, meaning there is no way to get any value out of it. You have only two options:

· Binding computations, or actions, to the monad so that they get executed later

· Running said computations to get the final result of your application

I imagine this may be pretty confusing if you have never seen an application created like this. The examples will try to give you a first impression of how it can be done and we will dive deeper into the topic in Chapter 11, Designing a Functional Application.

Motivation

The IO monad solves the issue of inputs and outputs breaking referential transparency and function purity by confining all IO operations within the monad. All computational steps needed for the application are first described in a functional way. Once this is done, we accept that the final step cannot be side-effect-free and we run all the sequences stored inside the monad.

Implementation

The implementation provided by php-functional library is pretty simple, as there are no real subtleties. There is only one little trick needed as the computation needs to be made when run method is called and not when the function is bound.

Besides that, the library comes with helper functions under the Widmogrod\Monad\IO namespace to help you use the monad. You can easily read input from the user on the command line, print text on the screen, and read and write files and environment variables.

Examples

We will take this opportunity to use the mcompose method in order to compose multiple IO operations together:

<?php

use Widmogrod\Functional as f;

use Widmogrod\Monad\IO;

use Widmogrod\Monad\Identity;

$readFromInput = f\mcompose(IO\putStrLn, IO\getLine, IO\putStrLn);

$readFromInput(Monad\Identity::of('Enter something and press <enter>'))->run();

// Enter something and press <enter>

// Hi!

// Hi!

So we first create a function that displays the current content of the monad using putStrLn, ask for some input, and display the result back.

The IO monad needs to wrap the whole computation of your application if you want to maintain referential transparency. This is because your inputs need to be retrieved through it and any output must also be done through the monad. This means we could show a lot of examples without really capturing the real essence of its use. This is why we will stop here and wait until Chapter 11, Designing a Functional Application, to see how it can be achieved.

Summary

In this chapter, we have looked at multiple monads and their implementation. I hope the examples made it clear how you can use them and what their benefits are:

· The Maybe monad can be used when a computation might return nothing

· The Either monad can be used when a computation might error

· The List monad can be used when a computation has multiple possible results

· The Writer monad can be used when some side information needs to be passed alongside the return value

· The Reader monad can be used to share a common environment between multiple computations

· The State monad is a beefed-up version of the Reader monad where the environment can be updated between each computation

· The IO monad can be used to perform IO operations in a referentially transparent way

There are, however, multiple other computations that can be simplified using monads. When writing code, I encourage you to take a step back and look at the structure to see if you recognize a monadic pattern. If so, you should probably implement it using our Monad class to benefit from what we've learned so far.

Also, those various monads can be used in combination to achieve complex transformations and computations. We will approach this topic in Chapter 10, PHP Frameworks and FP, where we will discuss monad transformers, and Chapter 11, Designing a Functional Application.

At this point in the book, you are perhaps impressed by some functional techniques but I imagine most of the things we've seen so far are a bit awkward and functional programming might seem tedious. The feeling is totally normal for two main reasons.

First, this awkwardness often results from some kind of missing abstraction or technique waiting to be discovered. If this were a book about Haskell, you would learn about all of these and you would have a handful of other books to look them up. However, this book is about PHP; we will learn a few more concepts in the later chapters, but after that, you will mostly be on your own, like a pioneer.

I can only encourage you to make your way through when you encounter those situations and look for patterns and ways to factor out commonalities in your code. Step by step, you will forge a great toolbox and things will get easier.

Second, all of this is probably new to you. Switching programming paradigm is really hard and it can be really frustrating. But fear not, with time, practice, and experience, you will gain confidence and the benefits will start to outweigh the cost. The steeper the learning curve, the greater the reward.

In the next chapter, we will discover some new functional concepts and patterns that will permit us to fully use the various techniques we have learned so far.