Monad transformers allow you to combine multiple monads into a single monad. Phunkie provides several monad transformers to help you work with nested monadic structures.
Monad transformers wrap one monad inside another, allowing you to work with both contexts simultaneously. For example, OptionT
wraps an Option
inside another monad F
.
Combines Option
with another monad:
use Phunkie\Cats\OptionT;
// ImmList<Option<Int>>
$listOfOptions = ImmList(Some(1), None(), Some(2));
$optionT = OptionT($listOfOptions);
// Map over the inner values
$result = $optionT->map(fn($x) => $x + 1);
// OptionT(ImmList(Some(2), None(), Some(3)))
// FlatMap with another OptionT
$result = $optionT->flatMap(
fn($x) => OptionT(ImmList(Some($x + 1)))
);
// OptionT(ImmList(Some(2), None(), Some(3)))
Combines State
with another monad:
use Phunkie\Cats\StateT;
// Some(State<Int, Int>)
$stateT = new StateT(Some(fn($n) => Some(Pair($n + 1, $n))));
$result = $stateT->run(1); // Some(Pair(2, 1))
Represents functions that return monadic values:
use Phunkie\Cats\Kleisli;
use function Phunkie\Functions\kleisli\kleisli;
$validateLength = kleisli(fn($s) =>
Option(strlen($s) > 3 ? $s : null)
);
$validateEmail = kleisli(fn($s) =>
Option(filter_var($s, FILTER_VALIDATE_EMAIL) ? $s : null)
);
// Compose validations
$validateInput = $validateLength->andThen($validateEmail);
$result = $validateInput->run("a@b"); // None
$result = $validateInput->run("user@example.com"); // Some("user@example.com")
Transform values within the nested structure:
$optionT->map(fn($x) => $x * 2);
$stateT->map(fn($x) => $x * 2);
Chain operations that return transformed values:
$optionT->flatMap(fn($x) => OptionT(Some($x * 2)));
$optionT->isDefined(); // F<Boolean>
$optionT->isEmpty(); // F<Boolean>
$optionT->getOrElse(42); // F<A>
$users = ImmList(
Some(['name' => 'Alice']),
None(),
Some(['name' => 'Bob'])
);
$names = OptionT($users)
->map(fn($user) => $user['name'])
->getOrElse('Unknown');
// ImmList('Alice', 'Unknown', 'Bob')
$computation = new StateT(
Some(fn($state) => Some(Pair($state + 1, $state)))
);
$validate = kleisli(fn($input) =>
Option($input)
->filter(fn($x) => strlen($x) > 3)
->filter(fn($x) => is_numeric($x))
);