A functor is a type class that represents the ability to map over a structure while preserving its shape. In Phunkie, functors provide a consistent way to transform values inside containers.
A functor is any type F<A>
that implements a map
operation which can transform values of type A
to type B
while preserving the structure of F
. The interface in Phunkie is:
interface Functor extends Invariant {
public function map(callable $f): Kind;
public function lift($f): callable;
public function as($b): Kind;
public function void(): Kind;
public function zipWith($f): Kind;
}
The fundamental operation of a functor:
// Option functor
$option = Some(42);
$result = $option->map(fn($x) => $x * 2); // Some(84)
// List functor
$list = ImmList(1, 2, 3);
$result = $list->map(fn($x) => $x * 2); // ImmList(2, 4, 6)
// Function functor
$f = Function1(fn($x) => $x + 1);
$g = $f->map(fn($x) => $x * 2); // Function1(fn($x) => ($x + 1) * 2)
Convert a function to work with functorial values:
$option = Some(42);
$lifted = $option->lift(fn($x) => $x + 1);
$result = $lifted(Some(42)); // Some(43)
Replace all values with a constant while preserving structure:
$list = ImmList(1, 2, 3);
$result = $list->as("a"); // ImmList("a", "a", "a")
Replace all values with Unit:
$option = Some(42);
$result = $option->void(); // Some(Unit())
Combine values with their transformed results:
$list = ImmList(1, 2, 3);
$result = $list->zipWith(fn($x) => $x * 2);
// ImmList(Pair(1, 2), Pair(2, 4), Pair(3, 6))
All functors must satisfy two fundamental laws:
fa->map(id) === fa
$list = ImmList(1, 2, 3);
$list->map(fn($x) => $x) === $list
fa->map(f)->map(g) === fa->map(fn($x) => g(f($x)))
```php
$f = fn($x) => $x + 1;
$g = fn($x) => $x * 2;$option = Some(42); $option->map($f)->map($g) === $option->map(fn($x) => $g($f($x)))
## Functor Composition
Functors can be composed to work with nested structures:
```php
use Phunkie\Cats\Functor\FunctorComposite;
// Compose Option and List functors
$f = new FunctorComposite(Option::kind);
$composed = $f->compose(ImmList::kind);
// Work with nested types
$data = ImmList(Some(1), None(), Some(2));
$result = $composed->map($data, fn($x) => $x + 1);
// ImmList(Some(2), None(), Some(3))