widmogrod/php-functional

View on GitHub
src/Monad/State.php

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
<?php

declare(strict_types=1);

namespace Widmogrod\Monad;

use Widmogrod\Common;
use FunctionalPHP\FantasyLand;

class State implements FantasyLand\Monad
{
    const of = 'Widmogrod\Monad\State::of';

    use Common\PointedTrait;

    /**
     * @param callable $continuation
     */
    public function __construct(callable $continuation)
    {
        $this->value = $continuation;
    }

    /**
     * @inheritdoc
     */
    public function ap(FantasyLand\Apply $b): FantasyLand\Apply
    {
        return $this->bind(function ($f) use ($b) {
            return $b->map($f);
        });
    }

    /**
     * @inheritdoc
     */
    public function bind(callable $function)
    {
        return self::of(function ($state) use ($function) {
            [$value, $newState] = $this->runState($state);
            $m = $function($value);

            return $m instanceof State
                ? $m->runState($newState)
                : [$m, $newState];
        });
    }

    /**
     * @inheritdoc
     */
    public function map(callable $function): FantasyLand\Functor
    {
        return self::of(function ($state) use ($function) {
            [$value, $newState] = $this->runState($state);

            return [$function($value), $newState];
        });
    }

    /**
     * runState :: s -> (a, s)
     *
     * Run computation on a monad with initial state
     *
     * @param mixed $initialState
     *
     * @return array
     */
    public function runState($initialState)
    {
        return call_user_func($this->value, $initialState);
    }
}