# Categories in OO: Functors

Today I’m starting my series on categories in OO. My goal is to explain these concepts to programmers who are already familiar with object-oriented programming, but new to functional programming.

I chose PHP for these examples because it’s many students’ first language in my country the Netherlands. I assume basic familiarity with concepts like first-class functions.

Let’s start with Functors.

Think of a simple value, perhaps the string `"apple"`

. Now apply a function to it:

<?php ucfirst("apple"); //=> "Apple"

Functors are contexts. They can contain any other value. Think of them like boxes.

Functors allow you to apply a function to their value with the `fmap`

method. `fmap`

takes a function, and applies it to the value inside the box. Functors may also have an `of`

method for construction. Functors with an `of`

method are called ‘pointed functors’.

<?php abstract class Functor { function __construct ($value) { $this->value = $value; } static function of ($val) { return new static($val); } abstract function fmap(Closure $f); } class Box extends Functor { function fmap(Closure $f) { return Box::of($f($this->value)); } }

Let’s try using it:

<?php $box = Box::of("apple")->fmap(function ($value) { return ucfirst($value); }); $box->value; //=> "Apple"

Our `Box`

isn’t very useful yet, but serves as the foundation for what’s to come. In this case, `fmap`

simply applies the function to the value, but it can really execute any code “behind the scenes”. By centralizing code within `fmap`

, we can reduce duplication in client code.

A more realistic example is the `Maybe`

type, commonly used to encapsulate an optional value. It’s power lies in the ability to treat presence and absence of a value equally, relieving client code of the burden of checking for nulls all the time.

<?php class Maybe extends Functor { function fmap(Closure $f) { return $this->isNothing() ? Maybe::of(null) : Maybe::of($f($this->value)); } function isNothing () { return $this->value === null; } }

To demonstrate:

<?php function add3 (Maybe $maybe) { return $maybe->fmap(function ($n) { return $n + 3; }); } // Null checking encapsulated: add3(Maybe::of(null)); //=> Maybe(null) add3(Maybe::of(5)); //=> Maybe(8) $maybe = Maybe::of("text"); // To get the value back out again: if (!$maybe->isNothing()) { doSomethingWith($just->value); }