...

/

Functors in PHP Programming

Functors in PHP Programming

Learn about functors as type classes and their properties using a calculator class coding example.

For languages like PHP that don’t have default userland functor supportA type class that implements functor-compatible methods is an effective replacement for the functor concept. The fantasyland package helps with functor compliance checks. It’s a PHP port of a more complex JavaScript package of the same name. In addition to the required functor design, the fantasyland project also includes verification of laws that functors must satisfy.

Functors are type classes

To effectively create a working functor, we need to implement the functor rubric—defined by category theory from the previous section—as a type class. A type class is a composite data type, which supports operator overloading. With a type class, it is possible to, with each invocation of a class method, overwrite its internal state and create a new immutable entity. Overriding in functors is expressed in the signatures of functions meant to be methods of the type class. Also referred to as ad-hoc polymorphism, operator overloading minimizes the redundancy of writing multiple methods to operationalize a new state. It truncates the boilerplate quite effectively.

Formally, a T class with an x parameter is a type class if the value of x can be influenced by a set of operations (functions) that maintain its type constraints. Type classes are interfaces that influence behavior in Haskell, a language that promotes type usage.

The Calculator class shown below is a simple demonstration of these ideas.

Press + to interact
<?php
class Calculator
{
private int $value;
public function __construct(int $value)
{
$this->value = $value;
}
public static function get(int $value): Calculator
{
return new static($value);
}
}
print_r(Calculator::get(1));

Type classes are immutable and ensure that every object generated by the get static method is atomic to the point of having isolated operations. Additionally, repeated constructor calls that effectively create new objects need not be made according to said conditions.

Adding a method to the type class that has a function as an input that acts on the internal class state operationalizes it as an as-needed polymorphic construct. Through the operation function, the class Calculator achieves the functor status.

Press + to interact
<?php
class Calculator
{
private int $value;
public function __construct(int $value)
{
$this->value = $value;
}
public static function get(int $value): Calculator
{
return new static($value);
}
public function operation(callable $operation): Calculator
{
return self::get($operation($this->value));
}
}
$obj = new Calculator(1);
print_r($obj->operation(fn (int $val): int => $val + 2));

It’s now possible to create logic chains with arithmetic expressions and demonstrate how to use the simple Calculator functor.

Press + to interact
<?php
$calc = Calculator::get(1)
->operation(fn (int $val): int => $val + 10)
->operation(fn (int $val): int => $val - 5)
->operation(fn (int $val): int => $val * 3);
print_r($calc);

The code in the snippet above is constrained to using integer values, unlike a real calculator. That said, the purpose of this example is to serve as a proof of ...