The State monad represents computations that carry state through a sequence of operations. In Phunkie, it provides a way to handle stateful computations in a pure functional manner.
A State monad wraps a function of type S -> Pair<S,A>
, where:
S
is the type of the stateA
is the type of the computed valuePair<S,A>
contains both the new state and the computed valueclass State {
public function __construct(callable $run) {
// run: S -> Pair<S,A>
}
}
Retrieves the current state:
use function Phunkie\Functions\state\get;
$state = get();
$result = $state->run(42); // Pair(42, 42)
Applies a function to the current state:
use function Phunkie\Functions\state\gets;
$state = gets(fn($x) => $x * 2);
$result = $state->run(21); // Pair(21, 42)
Replaces the state:
use function Phunkie\Functions\state\put;
$state = put(42);
$result = $state->run(10); // Pair(42, Unit())
// Initial state 10 is replaced with 42
Modifies the state using a function:
use function Phunkie\Functions\state\modify;
$state = modify(fn($x) => $x + 1);
$result = $state->run(41); // Pair(42, Unit())
Transform the computed value while keeping the state unchanged:
$state = State(42)->map(fn($x) => $x * 2);
$result = $state->run(0); // Pair(0, 84)
Chain state computations:
$state = State(21)->flatMap(
fn($x) => State($x * 2)
);
$result = $state->run(0); // Pair(0, 42)
$increment = modify(fn($n) => $n + 1)
->flatMap(fn($_) => get());
$result = $increment->run(41); // Pair(42, 42)
$push = fn($x) => modify(fn($stack) => array_merge([$x], $stack));
$pop = gets(fn($stack) => array_shift($stack));
$operations = $push(1)
->flatMap(fn($_) => $push(2))
->flatMap(fn($_) => $pop);
$result = $operations->run([]); // Pair([1], 2)
$updateUser = fn($id, $data) => gets(function($db) use ($id, $data) {
$db[$id] = array_merge($db[$id] ?? [], $data);
return $db;
});
$transaction = $updateUser(1, ["name" => "John"])
->flatMap(fn($db) => $updateUser(2, ["name" => "Jane"]));
StateT allows combining State with other monads:
use Phunkie\Cats\StateT;
$stateT = new StateT($monad);
$result = $stateT->map(fn($x) => $x * 2);