functional-php / fantasy-land

Specification for interoperability of common algebraic structures in PHP
BSD 3-Clause "New" or "Revised" License
34 stars 10 forks source link

Implement the right ap() method #16

Closed thomasvargiu closed 1 year ago

thomasvargiu commented 3 years ago

The ap() method in Apply isn't correct, but seems inverted.

it should be

ap :: Apply f => f a ~> f (a -> b) -> f b

Since the f (a -> b) should be the same of f a it's possible to implement the right method. This is an example of the Identity monad:

/**
 * @template T
 */
class Identity
{
   /**
     * @template U
     * @template C as callable(T): U
     *
     * @param FantasyLand\Apply<C> $applicative
     * @return FantasyLand\Apply<U>
     */
    public function ap2(FantasyLand\Apply $applicative): FantasyLand\Apply
    {
        if (! $applicative instanceof self) {
            throw new \LogicException(sprintf('Applicative must be an instance of %s', self::class));
        }
        return $applicative->bind(function (callable $f) {
            return self::of($f($this->value));
        });
    }
}

In this way it's statically correct too.

This is a BC, so a new 2.0 version is necessary.

AlexanderAllen commented 2 months ago

When copying some of these types to phpstan.org they don't compile.

For example: https://phpstan.org/r/75573289-03f7-4e7d-9142-5b28842872ea