From dbb5abf40d634c7c66b1c2a49baf0f403e307614 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Thu, 16 Dec 2021 15:59:04 +0100 Subject: [PATCH 01/28] Configure slevomat rule to be PSR12 compliant --- ruleset.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ruleset.xml b/ruleset.xml index adbf2bf..ac948f6 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -53,7 +53,11 @@ - + + + + + From 5ffed090b373ecb4420aa7f2247d0a41c10710e5 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Thu, 6 Jan 2022 15:00:44 +0100 Subject: [PATCH 02/28] Remove unhelping rule It is already checked with phpstan (and better) and it also didn't allow ommiting var name (which is totally valid) --- ruleset.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/ruleset.xml b/ruleset.xml index ac948f6..a2d33bc 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -92,7 +92,6 @@ - From 144092f5c52edb978b6448f8f34c96c278eab494 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Thu, 6 Jan 2022 15:01:55 +0100 Subject: [PATCH 03/28] Upgrade phpstan --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index ad0faf0..4e39c55 100644 --- a/composer.json +++ b/composer.json @@ -22,11 +22,11 @@ }, "require-dev": { "ergebnis/composer-normalize": "^2.0.2", - "phpstan/phpstan": "=1.1.2", + "phpstan/phpstan": "=1.3.1", "phpunit/phpunit": "^9.4.2", "slevomat/coding-standard": "^6.4.1", "squizlabs/php_codesniffer": "^3.5.0", - "bonami/phpstan-collections": "^0.4.x-dev" + "bonami/phpstan-collections": "^0.4.2" }, "config": { "bin-dir": "bin" From fdea269c7630556a9bbac7e3cb52797e657c5a0e Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Wed, 15 Dec 2021 22:58:30 +0100 Subject: [PATCH 04/28] [BC] Rework applicatives, monads, function currying This introduces some small abstraction over applicatives and mondas to help us build new typeclasses faster. Also I have reworked function currying to be able to do typehinting much better for curried functions --- src/Bonami/Collection/Applicative1.php | 106 +++++++++++++++ src/Bonami/Collection/Applicative2.php | 109 +++++++++++++++ src/Bonami/Collection/ArrayList.php | 125 +++-------------- src/Bonami/Collection/CurriedFunction.php | 128 ++++++++++++++++++ src/Bonami/Collection/Either.php | 100 ++------------ src/Bonami/Collection/Lambda.php | 90 ------------ src/Bonami/Collection/LazyList.php | 106 ++------------- src/Bonami/Collection/Monad1.php | 39 ++++++ src/Bonami/Collection/Monad2.php | 42 ++++++ src/Bonami/Collection/Option.php | 97 ++----------- src/Bonami/Collection/TrySafe.php | 107 ++------------- src/Bonami/Collection/helpers.php | 12 +- tests/Bonami/Collection/ArrayListTest.php | 42 +++--- .../Bonami/Collection/CurriedFunctionTest.php | 57 ++++++++ tests/Bonami/Collection/EitherTest.php | 54 +++++--- tests/Bonami/Collection/EnumTest.php | 2 +- tests/Bonami/Collection/LambdaTest.php | 84 ------------ tests/Bonami/Collection/LazyListTest.php | 45 +++--- tests/Bonami/Collection/OptionTest.php | 55 ++++---- tests/Bonami/Collection/TrySafeTest.php | 39 +++--- tests/Bonami/Collection/helpers.php | 44 +++--- 21 files changed, 714 insertions(+), 769 deletions(-) create mode 100644 src/Bonami/Collection/Applicative1.php create mode 100644 src/Bonami/Collection/Applicative2.php create mode 100644 src/Bonami/Collection/CurriedFunction.php delete mode 100644 src/Bonami/Collection/Lambda.php create mode 100644 src/Bonami/Collection/Monad1.php create mode 100644 src/Bonami/Collection/Monad2.php create mode 100644 tests/Bonami/Collection/CurriedFunctionTest.php delete mode 100644 tests/Bonami/Collection/LambdaTest.php diff --git a/src/Bonami/Collection/Applicative1.php b/src/Bonami/Collection/Applicative1.php new file mode 100644 index 0000000..ff18286 --- /dev/null +++ b/src/Bonami/Collection/Applicative1.php @@ -0,0 +1,106 @@ + + */ + abstract public static function pure($value); + + /** + * @template A + * @template B + * + * @param self $closure + * @param self $argument + * + * @return self + */ + abstract public static function ap(self $closure, self $argument): self; + + /** + * @template A + * + * @phpstan-param callable(T): A $mapper + * + * @phpstan-return self + */ + abstract public function map(callable $mapper): self; + + /** + * Upgrades callable to accept and return `self` as arguments. + * + * @phpstan-param callable $callable + * + * @phpstan-return callable + */ + final public static function lift(callable $callable): callable + { + return static function (self ...$arguments) use ($callable): self { + return self::sequence($arguments)->map(static function ($args) use ($callable) { + return $callable(...$args); + }); + }; + } + + /** + * Takes any `iterable>` and sequence it into `self>`. If any `self` is "empty", the result is + * "short circuited". + * + * @template A + * + * @phpstan-param iterable> $iterable + * + * @phpstan-return self> + */ + final public static function sequence(iterable $iterable): self + { + // @phpstan-ignore-next-line + return self::traverse($iterable, identity()); + } + + /** + * Takes any `iterable`, for each item `A` transforms to applicative with $mapperToApplicative + * `A => self` and cumulates it in `self>`. + * + * @see sequence - behaves same as traverse, execept it is called with identity + * + * @template A + * @template B + * + * @phpstan-param iterable $iterable + * @phpstan-param callable(A): self $mapperToApplicative + * + * @phpstan-return self> + */ + final public static function traverse(iterable $iterable, callable $mapperToApplicative): self + { + // @phpstan-ignore-next-line + return LazyList::fromIterable($iterable) + ->reduce( + static function (self $reducedApplicative, $impureItem) use ($mapperToApplicative): self { + $applicative = $mapperToApplicative($impureItem); + assert($applicative instanceof self); + return self::ap( + $reducedApplicative + ->map(static function (ArrayList $resultIterable): callable { + return CurriedFunction::of(static function ($item) use ($resultIterable): ArrayList { + return $resultIterable->concat(ArrayList::of($item)); + }); + }), + $applicative + ); + }, + self::pure(ArrayList::fromEmpty()) + ); + } +} diff --git a/src/Bonami/Collection/Applicative2.php b/src/Bonami/Collection/Applicative2.php new file mode 100644 index 0000000..f93dade --- /dev/null +++ b/src/Bonami/Collection/Applicative2.php @@ -0,0 +1,109 @@ + + */ + abstract public static function pure($value); + + /** + * @template A + * @template B + * + * @param self $closure + * @param self $argument + * + * @return self + */ + abstract public static function ap(self $closure, self $argument): self; + + /** + * @template A + * + * @param callable(R): A $mapper + * + * @phpstan-return self + */ + abstract public function map(callable $mapper): self; + + /** + * Upgrades callable to accept and return `self` as arguments. + * + * @phpstan-param callable $callable + * + * @phpstan-return callable + */ + final public static function lift(callable $callable): callable + { + return static function (self ...$arguments) use ($callable): self { + return self::sequence($arguments)->map(static function ($args) use ($callable) { + return $callable(...$args); + }); + }; + } + + /** + * Takes any `iterable>` and sequence it into `self>`. + * If any `self` is "empty", the result is "short circuited". + * + * @template A + * + * @phpstan-param iterable> $iterable + * + * @phpstan-return self> + */ + final public static function sequence(iterable $iterable): self + { + // @phpstan-ignore-next-line + return self::traverse($iterable, identity()); + } + + /** + * Takes any `iterable`, for each item `A` transforms to applicative with $mapperToApplicative + * `A => self` and cumulates it in `self>`. + * + * @see sequence - behaves same as traverse, execept it is called with identity + * + * @template A + * @template B + * + * @phpstan-param iterable $iterable + * @phpstan-param callable(A): self $mapperToApplicative + * + * @phpstan-return self> + */ + final public static function traverse(iterable $iterable, callable $mapperToApplicative): self + { + // @phpstan-ignore-next-line + return LazyList::fromIterable($iterable) + ->reduce( + static function (self $reducedApplicative, $impureItem) use ($mapperToApplicative): self { + $applicative = $mapperToApplicative($impureItem); + assert($applicative instanceof self); + return self::ap( + $reducedApplicative + ->map(static function (ArrayList $resultIterable): callable { + return CurriedFunction::of(static function ($item) use ($resultIterable): ArrayList { + return $resultIterable->concat(ArrayList::of($item)); + }); + }), + $applicative + ); + }, + self::pure(ArrayList::fromEmpty()) + ); + } +} diff --git a/src/Bonami/Collection/ArrayList.php b/src/Bonami/Collection/ArrayList.php index 0c5eb9d..7e1baac 100644 --- a/src/Bonami/Collection/ArrayList.php +++ b/src/Bonami/Collection/ArrayList.php @@ -43,6 +43,9 @@ */ class ArrayList implements Countable, IteratorAggregate, JsonSerializable { + /** @use Monad1 */ + use Monad1; + /** @phpstan-var array */ protected $items; @@ -80,6 +83,22 @@ public static function of(...$item) return new static(array_values($item)); } + /** + * Creates a List from single item + * + * Complexity: o(n) - where n is number of passed items + * + * @template V + * + * @phpstan-param V $item + * + * @phpstan-return static + */ + public static function pure($item) + { + return new static([$item]); + } + /** * Fill a list with $value * @@ -322,38 +341,6 @@ public function map(callable $mapper): self return new self(array_map($mapper, $this->items, array_keys($this->items))); } - /** - * Can be called only on ArrayList containing closures. (It will fail in runtime if - * this method is called on list which contains something different then callable) - * - * It will partially apply $values on each closure and returns partial functions. If - * the closures are fully applied, then results are returned. - * - * Note, that it will create combinations for each partial apply (number of final results - * are determined by number of closures and each $values list passed in partial apply. The - * number is multiplication of respective sizes) - * - * Complexity: o(n) - * - * @phpstan-param self $values - * - * @phpstan-return self - */ - public function ap(self $values): self - { - $mappers = $this->map(static function (callable $mapper): Lambda { - return Lambda::of($mapper); - }); - - return $values->flatMap(static function ($value) use ($mappers): self { - /** @phpstan-var self $applied */ - $applied = $mappers->map(static function (Lambda $mapper) use ($value) { - return ($mapper)($value); - }); - return $applied; - }); - } - /** * Creates a new List as result of mapping and then flattening the result. * @@ -1221,78 +1208,4 @@ public function __toString(): string }) ->join(', ') . ']'; } - - /** - * Upgrades callable to accept and return `self` as arguments. - * - * @phpstan-param callable $callable - * - * @phpstan-return callable - */ - final public static function lift(callable $callable): callable - { - return static function (self ...$arguments) use ($callable): self { - $reducer = static function (self $applicative, self $argument): self { - /** @phpstan-var mixed $argument */ - return $applicative->ap($argument); - }; - return LazyList::fromIterable($arguments) - ->reduce($reducer, self::of($callable)); - }; - } - - /** - * Takes any `iterable`, for each item `A` transforms to applicative with $mapperToApplicative - * `A => self` and cumulates it in `self>`. - * - * @see sequence - behaves same as traverse, execept it is called with identity - * - * @template A - * @template B - * - * @phpstan-param iterable $iterable - * @phpstan-param callable(A): self $mapperToApplicative - * - * @phpstan-return self> - */ - final public static function traverse(iterable $iterable, callable $mapperToApplicative): self - { - return LazyList::fromIterable($iterable) - ->reduce( - static function (self $reducedApplicative, $impureItem) use ($mapperToApplicative): self { - $applicative = $mapperToApplicative($impureItem); - assert($applicative instanceof self); - return $reducedApplicative - ->map(static function (ArrayList $resultIterable): callable { - return static function ($item) use ($resultIterable): ArrayList { - return $resultIterable->concat(ArrayList::of($item)); - }; - }) - ->ap($applicative); - }, - self::of(ArrayList::fromEmpty()) - ); - } - - /** - * Takes any `iterable>` and sequence it into `self>`. If any `self` is "empty", the result is - * "short circuited". - * - * E. g. when called upon Option, when any instance is a None, then result is None. - * If all instances are Some, the result is Some> - * - * @template A - * - * @phpstan-param iterable> $iterable - * - * @phpstan-return self> - */ - final public static function sequence(iterable $iterable): self - { - /** @phpstan-var callable(self): self $identity */ - $identity = static function ($a) { - return $a; - }; - return self::traverse($iterable, $identity); - } } diff --git a/src/Bonami/Collection/CurriedFunction.php b/src/Bonami/Collection/CurriedFunction.php new file mode 100644 index 0000000..8fd5aec --- /dev/null +++ b/src/Bonami/Collection/CurriedFunction.php @@ -0,0 +1,128 @@ + */ + protected $applied; + + /** @var int|null */ + protected $numberOfArgs; + + /** + * @phpstan-param callable $callable - closure to wrap and convert into curried closure + * @phpstan-param int $expectedNumberOfArgs - if ommited, number of arguments is detected + * with slight performance impact + * @phpstan-param array $applied - applied arguments tracked for delayed full aplication of final argument + */ + private function __construct(callable $callable, int $expectedNumberOfArgs, array $applied = []) + { + $numberOfArgs = (new ReflectionFunction(Closure::fromCallable($callable)))->getNumberOfParameters(); + if ($numberOfArgs !== $expectedNumberOfArgs) { + throw new InvalidStateException(sprintf( + 'Passed function must accept exactly %s arguments', + $expectedNumberOfArgs + )); + } + + $this->callable = $callable; + $this->numberOfArgs = $numberOfArgs; + $this->applied = $applied; + } + + /** + * @template A + * @template Z + * + * @param callable(A): Z $callable + * + * @return self + */ + public static function of(callable $callable): self + { + if ($callable instanceof self) { + return $callable; + } + return new self($callable, 1); + } + + /** + * @template A + * @template B + * @template Z + * + * @param callable(A, B): Z $callable + * + * @return self> + */ + public static function curry2(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 2); + } + + /** + * @template A + * @template B + * @template C + * @template Z + * + * @param callable(A, B, C): Z $callable + * + * @return self>> + */ + public static function curry3(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 3); + } + + /** + * Mapping over function is equivalent of composing functions + * + * @template A + * + * @param CurriedFunction $callable + * + * @return CurriedFunction + */ + public function map(CurriedFunction $callable): CurriedFunction + { + return self::of(function ($arg) use ($callable) { + return $callable($this($arg)); + }); + } + + /** + * @phpstan-param I $arg + * + * @phpstan-return O + */ + public function __invoke($arg) + { + if ($this->numberOfArgs === null) { + $this->numberOfArgs = (new ReflectionFunction( + Closure::fromCallable($this->callable) + ))->getNumberOfParameters(); + } + $newApplied = $this->applied; + $newApplied[] = $arg; + $numberOfArgsLeft = $this->numberOfArgs - count($newApplied); + + return $numberOfArgsLeft > 0 + ? new self($this->callable, $this->numberOfArgs, $newApplied) + : ($this->callable)(...$newApplied); + } +} diff --git a/src/Bonami/Collection/Either.php b/src/Bonami/Collection/Either.php index b1db170..73e4fe0 100644 --- a/src/Bonami/Collection/Either.php +++ b/src/Bonami/Collection/Either.php @@ -30,6 +30,9 @@ */ abstract class Either implements IHashable, IteratorAggregate { + /** @use Monad2 */ + use Monad2; + /** * @param L $left * @@ -67,11 +70,6 @@ public function mapLeft(callable $mapper): Either return self::left($mapper($this->left)); } - public function ap(Either $either): Either - { - return $this; - } - public function flatMap(callable $mapper): Either { return $this; @@ -218,14 +216,6 @@ public function isRight(): bool return true; } - public function ap(Either $either): Either - { - assert(is_callable($this->right)); - return $either->map(function ($value) { - return Lambda::of($this->right)($value); - }); - } - public function map(callable $mapper): Either { return self::of($mapper($this->right)); @@ -352,11 +342,11 @@ public function switch(): Either } /** - * @template B + * @template A * - * @param callable(R): B $mapper + * @param callable(R): A $mapper * - * @phpstan-return self + * @phpstan-return self */ abstract public function map(callable $mapper): self; @@ -382,83 +372,15 @@ final public static function of($value): self } /** - * Upgrades callable to accept and return `self` as arguments. - * - * @phpstan-param callable $callable - * - * @phpstan-return callable - */ - final public static function lift(callable $callable): callable - { - return static function (self ...$arguments) use ($callable): self { - $reducer = static function (self $applicative, self $argument): self { - /** @phpstan-var mixed $argument */ - return $applicative->ap($argument); - }; - return LazyList::fromIterable($arguments) - ->reduce($reducer, self::of($callable)); - }; - } - - /** - * @phpstan-param self $either - * - * @phpstan-return self - */ - abstract public function ap(self $either): self; - - /** - * Takes any `iterable>` and sequence it into `Either>`. - * If any `Either` is left instance, the result is "short circuited" and result is left. - * - * @template L2 - * @template R2 - * - * @phpstan-param iterable> $iterable - * - * @phpstan-return self> - */ - final public static function sequence(iterable $iterable): self - { - /** @phpstan-var callable(self): self $identity */ - $identity = static function ($a) { - return $a; - }; - return self::traverse($iterable, $identity); - } - - /** - * Takes any `iterable`, for each item `A` transforms to applicative with $mapperToApplicative - * `A => Either` and cumulates it in `Either>`. - * - * @see sequence - behaves same as traverse, execept it is called with identity - * - * @template A - * @template L2 - * @template R2 + * @template V * - * @phpstan-param iterable $iterable - * @phpstan-param callable(A): self $mapperToApplicative + * @param V $value * - * @phpstan-return self> + * @phpstan-return self */ - final public static function traverse(iterable $iterable, callable $mapperToApplicative): self + final public static function pure($value): self { - return LazyList::fromIterable($iterable) - ->reduce( - static function (self $reducedApplicative, $impureItem) use ($mapperToApplicative): self { - $applicative = $mapperToApplicative($impureItem); - assert($applicative instanceof self); - return $reducedApplicative - ->map(static function (ArrayList $resultIterable): callable { - return static function ($item) use ($resultIterable): ArrayList { - return $resultIterable->concat(ArrayList::of($item)); - }; - }) - ->ap($applicative); - }, - self::of(ArrayList::fromEmpty()) - ); + return self::right($value); } abstract public function isRight(): bool; diff --git a/src/Bonami/Collection/Lambda.php b/src/Bonami/Collection/Lambda.php deleted file mode 100644 index 9cde8f8..0000000 --- a/src/Bonami/Collection/Lambda.php +++ /dev/null @@ -1,90 +0,0 @@ - */ - protected $applied; - - /** @var int|null */ - protected $numberOfArgs; - - /** - * @phpstan-param callable $callable - closure to wrap and convert into curried closure - * @phpstan-param int|null $numberOfArgs - if ommited, number of arguments is detected - * with slight performance impact - * @phpstan-param array $applied - applied arguments tracked for delayed full aplication of final argument - */ - protected function __construct(callable $callable, ?int $numberOfArgs = null, array $applied = []) - { - $this->callable = $callable; - $this->numberOfArgs = $numberOfArgs; - $this->applied = $applied; - } - - public static function of(callable $callable): self - { - return $callable instanceof self ? $callable : new self($callable); - } - - /** - * Use this method instead of Lambda::of, if you dont want to use reflection - * to determine number of callable arguments. - * - * Calling ReflectionMethod can have some performance impact. - */ - public static function fromCallableWithNumberOfArgs(callable $callable, int $numberOfArgs): self - { - $isNumberOfArgsInvalid = $callable instanceof self - && $callable->numberOfArgs !== null - && ($callable->numberOfArgs - count($callable->applied) !== $numberOfArgs); - - if ($isNumberOfArgsInvalid) { - throw new InvalidStateException('Passed number of arguments seems to be invalid'); - } - - return $callable instanceof self ? $callable : new self($callable, $numberOfArgs); - } - - /** - * Mapping over function is equivalent of composing functions - */ - public function map(callable $callable): Lambda - { - return new self(compose($callable, $this->callable)); - } - - /** - * @phpstan-param mixed... $args - * - * @phpstan-return mixed - */ - public function __invoke(...$args) - { - if ($this->numberOfArgs === null) { - $this->numberOfArgs = (new ReflectionFunction( - Closure::fromCallable($this->callable) - ))->getNumberOfParameters(); - } - $newApplied = $this->applied; - foreach ($args as $arg) { - $newApplied[] = $arg; - } - $numberOfArgsLeft = $this->numberOfArgs - count($newApplied); - - return $numberOfArgsLeft > 0 - ? new self($this->callable, $this->numberOfArgs, $newApplied) - : ($this->callable)(...$newApplied); - } -} diff --git a/src/Bonami/Collection/LazyList.php b/src/Bonami/Collection/LazyList.php index 9bf4057..b4b1475 100644 --- a/src/Bonami/Collection/LazyList.php +++ b/src/Bonami/Collection/LazyList.php @@ -19,6 +19,9 @@ */ class LazyList implements IteratorAggregate { + /** @use Monad1 */ + use Monad1; + /** @phpstan-var iterable */ private $items; @@ -111,6 +114,18 @@ public static function of(...$items) return new static(array_values($items)); } + /** + * @template V + * + * @phpstan-param V $item + * + * @phpstan-return static + */ + public static function pure($item) + { + return new static([$item]); + } + /** * @template B * @@ -128,26 +143,6 @@ public function map(callable $mapper): self return new self($map($mapper)); } - /** - * @phpstan-param self $lazyList - * - * @phpstan-return self - */ - public function ap(self $lazyList): self - { - $mappers = $this->map(static function (callable $mapper) { - return Lambda::of($mapper); - })->toList(); - - return $lazyList->flatMap(static function ($value) use ($mappers): iterable { - /** @phpstan-var self $applied */ - $applied = $mappers->map(static function (Lambda $mapper) use ($value) { - return ($mapper)($value); - }); - return $applied; - }); - } - /** * @template B * @@ -645,75 +640,4 @@ private function createIterator(iterable $iterable): Iterator yield from $iterable; })($iterable); } - - /** - * Upgrades callable to accept and return `self` as arguments. - * - * @phpstan-param callable $callable - * - * @phpstan-return callable - */ - final public static function lift(callable $callable): callable - { - return static function (self ...$arguments) use ($callable): self { - $reducer = static function (self $applicative, self $argument): self { - /** @phpstan-var mixed $argument */ - return $applicative->ap($argument); - }; - return LazyList::fromIterable($arguments) - ->reduce($reducer, self::of($callable)); - }; - } - - /** - * Takes any `iterable`, for each item `A` transforms to applicative with $mapperToApplicative - * `A => self` and cumulates it in `self>`. - * - * @see sequence - behaves same as traverse, execept it is called with identity - * - * @template A - * @template B - * - * @phpstan-param iterable $iterable - * @phpstan-param callable(A): self $mapperToApplicative - * - * @phpstan-return self> - */ - final public static function traverse(iterable $iterable, callable $mapperToApplicative): self - { - return LazyList::fromIterable($iterable) - ->reduce( - static function (self $reducedApplicative, $impureItem) use ($mapperToApplicative): self { - $applicative = $mapperToApplicative($impureItem); - assert($applicative instanceof self); - return $reducedApplicative - ->map(static function (ArrayList $resultIterable): callable { - return static function ($item) use ($resultIterable): ArrayList { - return $resultIterable->concat(ArrayList::of($item)); - }; - }) - ->ap($applicative); - }, - self::of(ArrayList::fromEmpty()) - ); - } - - /** - * Takes any `iterable>` and sequence it into `LazyList>`. If any `LazyList` is empty, - * then the result is "short circuited" and empty LazyList is returned. - * - * @template A - * - * @phpstan-param iterable> $iterable - * - * @phpstan-return self> - */ - final public static function sequence(iterable $iterable): self - { - /** @phpstan-var callable(self): self $identity */ - $identity = static function ($a) { - return $a; - }; - return self::traverse($iterable, $identity); - } } diff --git a/src/Bonami/Collection/Monad1.php b/src/Bonami/Collection/Monad1.php new file mode 100644 index 0000000..c67977b --- /dev/null +++ b/src/Bonami/Collection/Monad1.php @@ -0,0 +1,39 @@ + */ + use Applicative1; + + /** + * @template A + * @template B + * + * @param self> $closure + * @param self $argument + * + * @return self + */ + final public static function ap(self $closure, self $argument): self + { + return $closure->flatMap(static function (CurriedFunction $c) use ($argument) { + return $argument->map(static function ($a) use ($c) { + return $c($a); + }); + }); + } + + /** + * @template B + * + * @phpstan-param callable(T, int): iterable $mapper + * + * @phpstan-return self + */ + abstract public function flatMap(callable $mapper): self; +} diff --git a/src/Bonami/Collection/Monad2.php b/src/Bonami/Collection/Monad2.php new file mode 100644 index 0000000..e640fa4 --- /dev/null +++ b/src/Bonami/Collection/Monad2.php @@ -0,0 +1,42 @@ + */ + use Applicative2; + + /** + * @template A + * @template B + * + * @param self> $closure + * @param self $argument + * + * @return self + */ + final public static function ap(self $closure, self $argument): self + { + return $closure->flatMap(static function ($c) use ($argument) { + return $argument->map(static function ($a) use ($c) { + return $c($a); + }); + }); + } + + /** + * @template B + * + * @phpstan-param callable(R, int): iterable $mapper + * + * @phpstan-return self + */ + abstract public function flatMap(callable $mapper): self; +} diff --git a/src/Bonami/Collection/Option.php b/src/Bonami/Collection/Option.php index b0cfdfe..6d7e3d5 100644 --- a/src/Bonami/Collection/Option.php +++ b/src/Bonami/Collection/Option.php @@ -18,6 +18,9 @@ */ abstract class Option implements IHashable, IteratorAggregate { + /** @use Monad1 */ + use Monad1; + /** @phpstan-var self|null */ private static $none; @@ -52,11 +55,6 @@ public function map(callable $mapper): Option return $this; } - public function ap(Option $option): Option - { - return $this; - } - public function flatMap(callable $mapper): Option { return $this; @@ -181,14 +179,6 @@ public function isEmpty(): bool return false; } - public function ap(Option $option): Option - { - assert(is_callable($this->value)); - return $option->map(function ($value) { - return Lambda::of($this->value)($value); - }); - } - public function map(callable $mapper): Option { return self::of($mapper($this->value)); @@ -310,90 +300,21 @@ abstract public function map(callable $mapper): self; * * @phpstan-return self */ - final public static function of($value): self + final public static function of($value) { return self::some($value); } /** - * Upgrades callable to accept and return `self` as arguments. - * - * @phpstan-param callable $callable - * - * @phpstan-return callable - */ - final public static function lift(callable $callable): callable - { - return static function (self ...$arguments) use ($callable): self { - $reducer = static function (self $applicative, self $argument): self { - /** @phpstan-var mixed $argument */ - return $applicative->ap($argument); - }; - return LazyList::fromIterable($arguments) - ->reduce($reducer, self::of($callable)); - }; - } - - /** - * @phpstan-param self $option - * - * @phpstan-return self - */ - abstract public function ap(self $option): self; - - /** - * Takes any `iterable>` and sequence it into `self>`. If any `self` is "empty", the result is - * "short circuited". - * - * When any instance is a None, then result is None. - * If all instances are Some, the result is Some> - * - * @template A - * - * @phpstan-param iterable> $iterable - * - * @phpstan-return self> - */ - final public static function sequence(iterable $iterable): self - { - /** @phpstan-var callable(self): self $identity */ - $identity = static function ($a) { - return $a; - }; - return self::traverse($iterable, $identity); - } - - /** - * Takes any `iterable`, for each item `A` transforms to applicative with $mapperToApplicative - * `A => self` and cumulates it in `self>`. - * - * @see sequence - behaves same as traverse, execept it is called with identity - * - * @template A - * @template B + * @template V * - * @phpstan-param iterable $iterable - * @phpstan-param callable(A): self $mapperToApplicative + * @phpstan-param V $value * - * @phpstan-return self> + * @phpstan-return self */ - final public static function traverse(iterable $iterable, callable $mapperToApplicative): self + final public static function pure($value) { - return LazyList::fromIterable($iterable) - ->reduce( - static function (self $reducedApplicative, $impureItem) use ($mapperToApplicative): self { - $applicative = $mapperToApplicative($impureItem); - assert($applicative instanceof self); - return $reducedApplicative - ->map(static function (ArrayList $resultIterable): callable { - return static function ($item) use ($resultIterable): ArrayList { - return $resultIterable->concat(ArrayList::of($item)); - }; - }) - ->ap($applicative); - }, - self::of(ArrayList::fromEmpty()) - ); + return self::some($value); } abstract public function isDefined(): bool; diff --git a/src/Bonami/Collection/TrySafe.php b/src/Bonami/Collection/TrySafe.php index d9d5932..370924f 100644 --- a/src/Bonami/Collection/TrySafe.php +++ b/src/Bonami/Collection/TrySafe.php @@ -19,6 +19,9 @@ */ abstract class TrySafe implements IHashable, IteratorAggregate { + /** @use Monad1 */ + use Monad1; + /** * @template V * @@ -31,6 +34,18 @@ final public static function of($value): self return self::success($value); } + /** + * @template V + * + * @phpstan-param V $value + * + * @phpstan-return self + */ + final public static function pure($value): self + { + return self::success($value); + } + /** * @template V * @@ -80,15 +95,6 @@ public function map(callable $mapper): TrySafe }); } - /** @inheritDoc */ - public function ap(TrySafe $trySafe): TrySafe - { - assert(is_callable($this->value)); - return $trySafe->map(function ($value) { - return Lambda::of($this->value)($value); - }); - } - /** @inheritDoc */ public function flatMap(callable $mapper): TrySafe { @@ -214,11 +220,6 @@ public function map(callable $mapper): TrySafe return $this; } - public function ap(TrySafe $trySafe): TrySafe - { - return $this; - } - public function flatMap(callable $mapper): TrySafe { return $this; @@ -335,13 +336,6 @@ public function hashCode() }; } - /** - * @phpstan-param self $trySafe - * - * @phpstan-return self - */ - abstract public function ap(self $trySafe): self; - /** * @template B * @@ -518,75 +512,4 @@ abstract public function toEither(): Either; * @phpstan-return B */ abstract public function resolve(callable $handleFailure, callable $handleSuccess); - - /** - * Upgrades callable to accept and return `self` as arguments. - * - * @phpstan-param callable $callable - * - * @phpstan-return callable - */ - final public static function lift(callable $callable): callable - { - return static function (self ...$arguments) use ($callable): self { - $reducer = static function (self $applicative, self $argument): self { - /** @phpstan-var mixed $argument */ - return $applicative->ap($argument); - }; - return LazyList::fromIterable($arguments) - ->reduce($reducer, self::of($callable)); - }; - } - - /** - * Takes any `iterable`, for each item `A` transforms to applicative with $mapperToApplicative - * `A => self` and cumulates it in `self>`. - * - * @see sequence - behaves same as traverse, execept it is called with identity - * - * @template A - * @template B - * - * @phpstan-param iterable $iterable - * @phpstan-param callable(A): self $mapperToApplicative - * - * @phpstan-return self> - */ - final public static function traverse(iterable $iterable, callable $mapperToApplicative): self - { - return LazyList::fromIterable($iterable) - ->reduce( - static function (self $reducedApplicative, $impureItem) use ($mapperToApplicative): self { - $applicative = $mapperToApplicative($impureItem); - assert($applicative instanceof self); - return $reducedApplicative - ->map(static function (ArrayList $resultIterable): callable { - return static function ($item) use ($resultIterable): ArrayList { - return $resultIterable->concat(ArrayList::of($item)); - }; - }) - ->ap($applicative); - }, - self::of(ArrayList::fromEmpty()) - ); - } - - /** - * Takes any `iterable>` and sequence it into `self>`. If any `self` is failure, the result is - * "short circuited" and result is first failure. - * - * @template A - * - * @phpstan-param iterable> $iterable - * - * @phpstan-return self> - */ - final public static function sequence(iterable $iterable): self - { - /** @phpstan-var callable(self): self $identity */ - $identity = static function ($a) { - return $a; - }; - return self::traverse($iterable, $identity); - } } diff --git a/src/Bonami/Collection/helpers.php b/src/Bonami/Collection/helpers.php index f590fe7..4be25b8 100644 --- a/src/Bonami/Collection/helpers.php +++ b/src/Bonami/Collection/helpers.php @@ -44,14 +44,16 @@ function falsy(): callable /** * Returns function that supplies $args as an arguments to passed function * - * @phpstan-param mixed... $args + * @template A + * + * @phpstan-param A $arg $args * - * @phpstan-return callable + * @phpstan-return callable(callable(A): mixed): mixed */ -function applicator(...$args): callable +function applicator1($arg): callable { - return static function (callable $callable) use ($args) { - return $callable(...$args); + return static function (callable $callable) use ($arg) { + return $callable($arg); }; } diff --git a/tests/Bonami/Collection/ArrayListTest.php b/tests/Bonami/Collection/ArrayListTest.php index b663ba7..b6eec56 100644 --- a/tests/Bonami/Collection/ArrayListTest.php +++ b/tests/Bonami/Collection/ArrayListTest.php @@ -108,27 +108,26 @@ public function testMap(): void public function testAp(): void { + /** @var ArrayList>>> */ $callbacks = ArrayList::fromIterable([ - static function ($a, $b) { + CurriedFunction::curry2(static function ($a, $b) { return $a . $b; - }, - static function ($a, $b) { + }), + CurriedFunction::curry2(static function ($a, $b) { return [$a, $b]; - }, + }), ]); - $mapped = $callbacks - ->ap(ArrayList::of(1, 2)) - ->ap(ArrayList::of('a', 'b')); + $mapped = ArrayList::ap(ArrayList::ap($callbacks, ArrayList::of('1', '2')), ArrayList::of('a', 'b')); $expected = [ '1a', - [1, 'a'], - '2a', - [2, 'a'], '1b', - [1, 'b'], + '2a', '2b', - [2, 'b'], + ['1', 'a'], + ['1', 'b'], + ['2', 'a'], + ['2', 'b'], ]; self::assertEquals($expected, $mapped->toArray()); @@ -136,17 +135,18 @@ static function ($a, $b) { public function testApNone(): void { + /** @var ArrayList>>> */ $callbacks = ArrayList::fromIterable([ - static function ($a, $b) { + CurriedFunction::curry2(static function ($a, $b) { return $a . $b; - }, - static function ($a, $b) { + }), + CurriedFunction::curry2(static function ($a, $b) { return [$a, $b]; - }, + }), ]); - $mapped = $callbacks - ->ap(ArrayList::of(1, 2)) - ->ap(ArrayList::fromEmpty()); + /** @var ArrayList */ + $strings = ArrayList::fromEmpty(); + $mapped = ArrayList::ap(ArrayList::ap($callbacks, ArrayList::of('1', '2')), $strings); self::assertEquals([], $mapped->toArray()); } @@ -159,7 +159,7 @@ public function testLift(): void $mapped = $lifted(ArrayList::of(1, 2), ArrayList::of('a', 'b')); - self::assertEquals(['1a', '2a', '1b', '2b'], $mapped->toArray()); + self::assertEquals(['1a', '1b', '2a', '2b'], $mapped->toArray()); } public function testTraverse(): void @@ -192,8 +192,8 @@ public function testSequenceWithMultipleValues(): void self::assertEquals( ArrayList::of( ArrayList::fromIterable([1, 'a']), - ArrayList::fromIterable([2, 'a']), ArrayList::fromIterable([1, 'b']), + ArrayList::fromIterable([2, 'a']), ArrayList::fromIterable([2, 'b']), ), ArrayList::sequence([$a, $b]) diff --git a/tests/Bonami/Collection/CurriedFunctionTest.php b/tests/Bonami/Collection/CurriedFunctionTest.php new file mode 100644 index 0000000..d833474 --- /dev/null +++ b/tests/Bonami/Collection/CurriedFunctionTest.php @@ -0,0 +1,57 @@ +map($countChars)('World')); + } + + public function testItShouldNotRewrapAlreadyWrapped(): void + { + $curried = CurriedFunction::curry2(static function (int $a, int $b): int { + return $a + $b; + }); + + $plus5 = $curried(5); + self::assertSame($plus5, CurriedFunction::of($plus5)); + } +} diff --git a/tests/Bonami/Collection/EitherTest.php b/tests/Bonami/Collection/EitherTest.php index 1b57e4d..4c8c7cb 100644 --- a/tests/Bonami/Collection/EitherTest.php +++ b/tests/Bonami/Collection/EitherTest.php @@ -277,21 +277,27 @@ public function testTapLeft(): void public function testAp(): void { - $plus = static function (int $x, int $y): int { + $plus = CurriedFunction::curry2(static function (int $x, int $y): int { return $x + $y; - }; + }); + /** @var Either>> */ + $leftOp = Either::left('undefined operation'); $purePlus = Either::of($plus); - $left = Either::left(666); + /** @var Either */ + $left = Either::left('missing value'); + /** @var Either */ $one = Either::right(1); + /** @var Either */ $two = Either::right(2); + /** @var Either */ $three = Either::right(3); - $this->equals($purePlus->ap($one)->ap($two), $three); - $this->equals($purePlus->ap($one)->ap($left), $left); - $this->equals($purePlus->ap($left)->ap($one), $left); - $this->equals($purePlus->ap($left)->ap($left), $left); - $this->equals($left->ap($one)->ap($two), $left); + $this->equals(Either::ap(Either::ap($purePlus, $one), $two), $three); + $this->equals(Either::ap(Either::ap($purePlus, $one), $left), $left); + $this->equals(Either::ap(Either::ap($purePlus, $left), $one), $left); + $this->equals(Either::ap(Either::ap($purePlus, $left), $left), $left); + $this->equals(Either::ap(Either::ap($leftOp, $one), $two), $leftOp); } public function testTraverse(): void @@ -401,6 +407,10 @@ public function testLaws(): void $eitherEquals = static function (Either $a, Either $b): bool { return $a->equals($b); }; + $ap = static function (Either $a, Either $b): Either { + // @phpstan-ignore-next-line + return Either::ap($a, $b); + }; $pure = static function ($value): Either { return Either::of($value); }; @@ -410,12 +420,12 @@ public function testLaws(): void $rightThree = Either::right(3); $error = Either::left('error'); - $plus2 = static function (int $x): int { + $plus2 = CurriedFunction::of(static function (int $x): int { return $x + 2; - }; - $multiple2 = static function (int $x): int { + }); + $multiple2 = CurriedFunction::of(static function (int $x): int { return $x * 2; - }; + }); testEqualsReflexivity($assertEquals, $eitherEquals, $rightOne); testEqualsReflexivity($assertEquals, $eitherEquals, $error); @@ -435,19 +445,19 @@ public function testLaws(): void testFunctorComposition($assertEquals, $rightOne, $plus2, $multiple2); testFunctorComposition($assertEquals, $error, $plus2, $multiple2); - testApplicativeIdentity($assertEquals, $pure, $rightOne); - testApplicativeIdentity($assertEquals, $pure, $error); + testApplicativeIdentity($assertEquals, $ap, $pure, $rightOne); + testApplicativeIdentity($assertEquals, $ap, $pure, $error); - testApplicativeHomomorphism($assertEquals, $pure, 666, $multiple2); - testApplicativeHomomorphism($assertEquals, $pure, 666, $multiple2); + testApplicativeHomomorphism($assertEquals, $ap, $pure, 666, $multiple2); + testApplicativeHomomorphism($assertEquals, $ap, $pure, 666, $multiple2); - testApplicativeComposition($assertEquals, $pure, $rightOne, $pure($plus2), $pure($multiple2)); - testApplicativeComposition($assertEquals, $pure, $error, $pure($plus2), $pure($multiple2)); - testApplicativeComposition($assertEquals, $pure, $rightOne, $error, $pure($multiple2)); - testApplicativeComposition($assertEquals, $pure, $error, $pure($plus2), $error); + testApplicativeComposition($assertEquals, $ap, $pure, $rightOne, $pure($plus2), $pure($multiple2)); + testApplicativeComposition($assertEquals, $ap, $pure, $error, $pure($plus2), $pure($multiple2)); + testApplicativeComposition($assertEquals, $ap, $pure, $rightOne, $error, $pure($multiple2)); + testApplicativeComposition($assertEquals, $ap, $pure, $error, $pure($plus2), $error); - testApplicativeInterchange($assertEquals, $pure, 666, $pure($plus2)); - testApplicativeInterchange($assertEquals, $pure, 666, $error); + testApplicativeInterchange($assertEquals, $ap, $pure, 666, $pure($plus2)); + testApplicativeInterchange($assertEquals, $ap, $pure, 666, $error); } /** diff --git a/tests/Bonami/Collection/EnumTest.php b/tests/Bonami/Collection/EnumTest.php index a3a62d1..7820041 100644 --- a/tests/Bonami/Collection/EnumTest.php +++ b/tests/Bonami/Collection/EnumTest.php @@ -56,7 +56,7 @@ public function testGetListComplement(): void public function testJsonSerializable(): void { - $serialized = json_encode(['foo' => TestEnum::create(TestEnum::A)]); + $serialized = json_encode(['foo' => TestEnum::create(TestEnum::A)], JSON_THROW_ON_ERROR); assert(is_string($serialized)); self::assertJson('{"foo": "A"}', $serialized); } diff --git a/tests/Bonami/Collection/LambdaTest.php b/tests/Bonami/Collection/LambdaTest.php deleted file mode 100644 index 796732b..0000000 --- a/tests/Bonami/Collection/LambdaTest.php +++ /dev/null @@ -1,84 +0,0 @@ -map($countChars)('World')); - } - - public function testFromCallableWithNumberOfArgsDontWrapMultipleTimes(): void - { - $curried = Lambda::of(static function (int $a, int $b): int { - return $a + $b; - }); - - $plus5 = $curried(5); - self::assertSame($plus5, Lambda::fromCallableWithNumberOfArgs($plus5, 1)); - } - - public function testFromCallableWithNumberOfArgsThrowsOnInvalidNumberOfArgs(): void - { - $this->expectException(InvalidStateException::class); - $curried = Lambda::of(static function (int $a, int $b): int { - return $a + $b; - }); - - $plus5 = $curried(5); - self::assertSame($plus5, Lambda::fromCallableWithNumberOfArgs($plus5, 2)); - } -} diff --git a/tests/Bonami/Collection/LazyListTest.php b/tests/Bonami/Collection/LazyListTest.php index 33aa66d..7a1651a 100644 --- a/tests/Bonami/Collection/LazyListTest.php +++ b/tests/Bonami/Collection/LazyListTest.php @@ -90,45 +90,46 @@ public function testMapWithKey(): void public function testAp(): void { + /** @var LazyList>>> */ $callbacks = LazyList::fromIterable([ - static function ($a, $b) { + CurriedFunction::curry2(static function ($a, $b) { return $a . $b; - }, - static function ($a, $b) { + }), + CurriedFunction::curry2(static function ($a, $b) { return [$a, $b]; - }, + }), ]); - $mapped = $callbacks - ->ap(LazyList::of(1, 2)) - ->ap(LazyList::of('a', 'b')); + $numbersApplied = LazyList::ap($callbacks, LazyList::of('1', '2')); + $lettersApplied = LazyList::ap($numbersApplied, LazyList::of('a', 'b')); $expected = [ '1a', - [1, 'a'], - '2a', - [2, 'a'], '1b', - [1, 'b'], + '2a', '2b', - [2, 'b'], + ['1', 'a'], + ['1', 'b'], + ['2', 'a'], + ['2', 'b'], ]; - self::assertEquals($expected, $mapped->toArray()); + self::assertEquals($expected, $lettersApplied->toArray()); } public function testApNone(): void { + /** @var LazyList>>> */ $callbacks = LazyList::fromIterable([ - static function ($a, $b) { + CurriedFunction::curry2(static function ($a, $b) { return $a . $b; - }, - static function ($a, $b) { + }), + CurriedFunction::curry2(static function ($a, $b) { return [$a, $b]; - }, + }), ]); - $mapped = $callbacks - ->ap(LazyList::of(1, 2)) - ->ap(LazyList::fromEmpty()); + /** @var LazyList $empty */ + $empty = LazyList::fromEmpty(); + $mapped = LazyList::ap(LazyList::ap($callbacks, LazyList::of('1', '2')), $empty); self::assertEquals([], $mapped->toArray()); } @@ -141,7 +142,7 @@ public function testLift(): void $mapped = $lifted(LazyList::of(1, 2), LazyList::of('a', 'b')); - self::assertEquals(['1a', '2a', '1b', '2b'], $mapped->toArray()); + self::assertEquals(['1a', '1b', '2a', '2b'], $mapped->toArray()); } public function testSequence(): void @@ -169,8 +170,8 @@ public function testSequenceWithMultipleValues(): void self::assertEquals( [ ArrayList::fromIterable([1, 'a']), - ArrayList::fromIterable([2, 'a']), ArrayList::fromIterable([1, 'b']), + ArrayList::fromIterable([2, 'a']), ArrayList::fromIterable([2, 'b']), ], LazyList::sequence($iterable)->toArray() diff --git a/tests/Bonami/Collection/OptionTest.php b/tests/Bonami/Collection/OptionTest.php index f7e71b1..cd60c02 100644 --- a/tests/Bonami/Collection/OptionTest.php +++ b/tests/Bonami/Collection/OptionTest.php @@ -288,21 +288,23 @@ public function testTapNone(): void public function testAp(): void { - $plus = static function (int $x, int $y): int { + $purePlus = Option::of(CurriedFunction::curry2(static function (int $x, int $y): int { return $x + $y; - }; - - $purePlus = Option::of($plus); - $none = Option::none(); + })); + /** @var Option $noneInt */ + $noneInt = Option::none(); $one = Option::some(1); $two = Option::some(2); $three = Option::some(3); - $this->equals($purePlus->ap($one)->ap($two), $three); - $this->equals($purePlus->ap($one)->ap($none), $none); - $this->equals($purePlus->ap($none)->ap($one), $none); - $this->equals($purePlus->ap($none)->ap($none), $none); - $this->equals($none->ap($one)->ap($two), $none); + /** @var Option>> $noneClosure */ + $noneClosure = Option::none(); + + $this->equals(Option::ap(Option::ap($purePlus, $one), $two), $three); + $this->equals(Option::ap(Option::ap($purePlus, $one), $noneInt), $noneInt); + $this->equals(Option::ap(Option::ap($purePlus, $noneInt), $one), $noneInt); + $this->equals(Option::ap(Option::ap($purePlus, $noneInt), $noneInt), $noneInt); + $this->equals(Option::ap(Option::ap($noneClosure, $one), $two), $noneInt); } public function testTraverse(): void @@ -404,12 +406,17 @@ public function testResolveNone(): void public function testLaws(): void { + $assertEquals = function ($a, $b): void { $this->equals($a, $b); }; $optionEquals = static function (Option $a, Option $b): bool { return $a->equals($b); }; + $ap = static function (Option $a, Option $b): Option { + // @phpstan-ignore-next-line + return Option::ap($a, $b); + }; $pure = static function ($value): Option { return Option::of($value); }; @@ -419,12 +426,12 @@ public function testLaws(): void $someThree = Option::some(3); $none = Option::none(); - $plus2 = static function (int $x): int { + $plus2 = CurriedFunction::of(static function (int $x): int { return $x + 2; - }; - $multiple2 = static function (int $x): int { + }); + $multiple2 = CurriedFunction::of(static function (int $x): int { return $x * 2; - }; + }); testEqualsReflexivity($assertEquals, $optionEquals, $someOne); testEqualsReflexivity($assertEquals, $optionEquals, $none); @@ -444,19 +451,19 @@ public function testLaws(): void testFunctorComposition($assertEquals, $someOne, $plus2, $multiple2); testFunctorComposition($assertEquals, $none, $plus2, $multiple2); - testApplicativeIdentity($assertEquals, $pure, $someOne); - testApplicativeIdentity($assertEquals, $pure, $none); + testApplicativeIdentity($assertEquals, $ap, $pure, $someOne); + testApplicativeIdentity($assertEquals, $ap, $pure, $none); - testApplicativeHomomorphism($assertEquals, $pure, 666, $multiple2); - testApplicativeHomomorphism($assertEquals, $pure, 666, $multiple2); + testApplicativeHomomorphism($assertEquals, $ap, $pure, 666, $multiple2); + testApplicativeHomomorphism($assertEquals, $ap, $pure, 666, $multiple2); - testApplicativeComposition($assertEquals, $pure, $someOne, $pure($plus2), $pure($multiple2)); - testApplicativeComposition($assertEquals, $pure, $none, $pure($plus2), $pure($multiple2)); - testApplicativeComposition($assertEquals, $pure, $someOne, $none, $pure($multiple2)); - testApplicativeComposition($assertEquals, $pure, $none, $pure($plus2), $none); + testApplicativeComposition($assertEquals, $ap, $pure, $someOne, $pure($plus2), $pure($multiple2)); + testApplicativeComposition($assertEquals, $ap, $pure, $none, $pure($plus2), $pure($multiple2)); + testApplicativeComposition($assertEquals, $ap, $pure, $someOne, $none, $pure($multiple2)); + testApplicativeComposition($assertEquals, $ap, $pure, $none, $pure($plus2), $none); - testApplicativeInterchange($assertEquals, $pure, 666, $pure($plus2)); - testApplicativeInterchange($assertEquals, $pure, 666, $none); + testApplicativeInterchange($assertEquals, $ap, $pure, 666, $pure($plus2)); + testApplicativeInterchange($assertEquals, $ap, $pure, 666, $none); } /** diff --git a/tests/Bonami/Collection/TrySafeTest.php b/tests/Bonami/Collection/TrySafeTest.php index bae220a..acc709a 100644 --- a/tests/Bonami/Collection/TrySafeTest.php +++ b/tests/Bonami/Collection/TrySafeTest.php @@ -366,6 +366,11 @@ public function testLaws(): void $tryEquals = static function (TrySafe $a, TrySafe $b): bool { return $a->equals($b); }; + + $ap = static function (TrySafe $a, TrySafe $b): TrySafe { + // @phpstan-ignore-next-line + return TrySafe::ap($a, $b); + }; $pure = static function ($value): TrySafe { return TrySafe::of($value); }; @@ -375,15 +380,15 @@ public function testLaws(): void $successThree = TrySafe::success(3); $failure = $this->createFailure(); - $plus2 = static function (int $x): int { + $plus2 = CurriedFunction::of(static function (int $x): int { return $x + 2; - }; - $multiple2 = static function (int $x): int { + }); + $multiple2 = CurriedFunction::of(static function (int $x): int { return $x * 2; - }; - $throws = function () { + }); + $throws = CurriedFunction::of(function (int $_) { throw $this->createHashableException(); - }; + }); testEqualsReflexivity($assertEquals, $tryEquals, $successOne); testEqualsReflexivity($assertEquals, $tryEquals, $failure); @@ -409,20 +414,20 @@ public function testLaws(): void testFunctorComposition($assertEquals, $successOne, $throws, $throws); testFunctorComposition($assertEquals, $failure, $throws, $throws); - testApplicativeIdentity($assertEquals, $pure, $successOne); - testApplicativeIdentity($assertEquals, $pure, $failure); + testApplicativeIdentity($assertEquals, $ap, $pure, $successOne); + testApplicativeIdentity($assertEquals, $ap, $pure, $failure); - testApplicativeHomomorphism($assertEquals, $pure, 666, $multiple2); - testApplicativeHomomorphism($assertEquals, $pure, 666, $multiple2); + testApplicativeHomomorphism($assertEquals, $ap, $pure, 666, $multiple2); + testApplicativeHomomorphism($assertEquals, $ap, $pure, 666, $multiple2); - testApplicativeComposition($assertEquals, $pure, $successOne, $pure($plus2), $pure($multiple2)); - testApplicativeComposition($assertEquals, $pure, $failure, $pure($plus2), $pure($multiple2)); - testApplicativeComposition($assertEquals, $pure, $successOne, $failure, $pure($multiple2)); - testApplicativeComposition($assertEquals, $pure, $failure, $pure($plus2), $failure); + testApplicativeComposition($assertEquals, $ap, $pure, $successOne, $pure($plus2), $pure($multiple2)); + testApplicativeComposition($assertEquals, $ap, $pure, $failure, $pure($plus2), $pure($multiple2)); + testApplicativeComposition($assertEquals, $ap, $pure, $successOne, $failure, $pure($multiple2)); + testApplicativeComposition($assertEquals, $ap, $pure, $failure, $pure($plus2), $failure); - testApplicativeInterchange($assertEquals, $pure, 666, $pure($plus2)); - testApplicativeInterchange($assertEquals, $pure, 666, $pure($throws)); - testApplicativeInterchange($assertEquals, $pure, 666, $failure); + testApplicativeInterchange($assertEquals, $ap, $pure, 666, $pure($plus2)); + testApplicativeInterchange($assertEquals, $ap, $pure, 666, $pure($throws)); + testApplicativeInterchange($assertEquals, $ap, $pure, 666, $failure); } /** diff --git a/tests/Bonami/Collection/helpers.php b/tests/Bonami/Collection/helpers.php index ca9fcfe..e9e52e2 100644 --- a/tests/Bonami/Collection/helpers.php +++ b/tests/Bonami/Collection/helpers.php @@ -77,16 +77,16 @@ function testFunctorIdentity(callable $assertEquals, $functor): void /** * @phpstan-param callable(mixed, mixed): void $assertEquals * @phpstan-param mixed $functor - this should implement some generic functor interface - * @phpstan-param callable(mixed): mixed $f - * @phpstan-param callable(mixed): mixed $g + * @phpstan-param CurriedFunction $f + * @phpstan-param CurriedFunction $g * * @phpstan-return void */ -function testFunctorComposition(callable $assertEquals, $functor, callable $f, callable $g): void +function testFunctorComposition(callable $assertEquals, $functor, CurriedFunction $f, CurriedFunction $g): void { $assertEquals( $functor->map($g)->map($f), - $functor->map(compose($f, $g)) + $functor->map($g->map($f)) ); } @@ -94,53 +94,62 @@ function testFunctorComposition(callable $assertEquals, $functor, callable $f, c /** * @phpstan-param callable(mixed, mixed): void $assertEquals + * @phpstan-param callable(mixed, mixed): mixed $ap * @phpstan-param callable(mixed): mixed $pure * @phpstan-param mixed $applicative - this should implement some generic applicative interface * * @phpstan-return void */ -function testApplicativeIdentity(callable $assertEquals, callable $pure, $applicative): void +function testApplicativeIdentity(callable $assertEquals, callable $ap, callable $pure, $applicative): void { $assertEquals( - $pure(identity())->ap($applicative), + $ap($pure(CurriedFunction::of(identity())), $applicative), $applicative ); } /** * @phpstan-param callable(mixed, mixed): void $assertEquals + * @phpstan-param callable(mixed, mixed): mixed $ap * @phpstan-param callable(mixed): mixed $pure * @phpstan-param mixed $value - * @phpstan-param callable(mixed): mixed $f + * @phpstan-param CurriedFunction $f * * @phpstan-return void */ -function testApplicativeHomomorphism(callable $assertEquals, callable $pure, $value, callable $f): void -{ +function testApplicativeHomomorphism( + callable $assertEquals, + callable $ap, + callable $pure, + $value, + CurriedFunction $f +): void { $assertEquals( - $pure($f)->ap($pure($value)), + $ap($pure($f), $pure($value)), $pure($f($value)) ); } /** * @phpstan-param callable(mixed, mixed): void $assertEquals + * @phpstan-param callable(mixed, mixed): mixed $ap * @phpstan-param callable(mixed): mixed $pure * @phpstan-param mixed $value * @phpstan-param mixed $applicativeF - this should implement some generic applicative interface * * @phpstan-return void */ -function testApplicativeInterchange(callable $assertEquals, callable $pure, $value, $applicativeF): void +function testApplicativeInterchange(callable $assertEquals, callable $ap, callable $pure, $value, $applicativeF): void { $assertEquals( - $applicativeF->ap($pure($value)), - $pure(applicator($value))->ap($applicativeF) + $ap($applicativeF, $pure($value)), + $ap($pure(CurriedFunction::of(applicator1($value))), $applicativeF), ); } /** * @phpstan-param callable(mixed, mixed): void $assertEquals + * @phpstan-param callable(mixed, mixed): mixed $ap * @phpstan-param callable(mixed): mixed $pure * @phpstan-param mixed $applicative - this should implement some generic applicative interface * @phpstan-param mixed $applicativeF - this should implement some generic applicative interface @@ -150,18 +159,19 @@ function testApplicativeInterchange(callable $assertEquals, callable $pure, $val */ function testApplicativeComposition( callable $assertEquals, + callable $ap, callable $pure, $applicative, $applicativeF, $applicativeG ): void { - $curriedComposition = Lambda::of(static function (callable $f, callable $g): callable { - return compose($f, $g); + $curriedComposition = CurriedFunction::curry2(static function (CurriedFunction $f, CurriedFunction $g): callable { + return $g->map($f); }); $assertEquals( - $pure($curriedComposition)->ap($applicativeF)->ap($applicativeG)->ap($applicative), - $applicativeF->ap($applicativeG->ap($applicative)) + $ap($ap($ap($pure($curriedComposition), $applicativeF), $applicativeG), $applicative), + $ap($applicativeF, $ap($applicativeG, $applicative)), ); } From a83a27c850ee8f331334e5ee60f3839261c61749 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Thu, 6 Jan 2022 15:15:48 +0100 Subject: [PATCH 05/28] Add some doc on monad/applicative abstraction --- src/Bonami/Collection/Applicative1.php | 8 +++++++- src/Bonami/Collection/Applicative2.php | 8 +++++++- src/Bonami/Collection/Monad1.php | 5 +++++ src/Bonami/Collection/Monad2.php | 5 +++++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/Bonami/Collection/Applicative1.php b/src/Bonami/Collection/Applicative1.php index ff18286..706faab 100644 --- a/src/Bonami/Collection/Applicative1.php +++ b/src/Bonami/Collection/Applicative1.php @@ -8,6 +8,8 @@ trait Applicative1 { /** + * Wraps impure item into pure context of type class. + * * @template A * * @phpstan-param A $value @@ -17,6 +19,8 @@ trait Applicative1 abstract public static function pure($value); /** + * Applies argument to callable in context of type class. + * * @template A * @template B * @@ -28,6 +32,8 @@ abstract public static function pure($value); abstract public static function ap(self $closure, self $argument): self; /** + * Maps over values wrapped in context of type class. + * * @template A * * @phpstan-param callable(T): A $mapper @@ -54,7 +60,7 @@ final public static function lift(callable $callable): callable /** * Takes any `iterable>` and sequence it into `self>`. If any `self` is "empty", the result is - * "short circuited". + * "empty" as well. * * @template A * diff --git a/src/Bonami/Collection/Applicative2.php b/src/Bonami/Collection/Applicative2.php index f93dade..d685da2 100644 --- a/src/Bonami/Collection/Applicative2.php +++ b/src/Bonami/Collection/Applicative2.php @@ -11,6 +11,8 @@ trait Applicative2 { /** + * Wraps impure item into pure context of type class. + * * @template A * * @phpstan-param A $value @@ -20,6 +22,8 @@ trait Applicative2 abstract public static function pure($value); /** + * Applies argument to callable in context of type class. + * * @template A * @template B * @@ -31,6 +35,8 @@ abstract public static function pure($value); abstract public static function ap(self $closure, self $argument): self; /** + * Maps over values wrapped in context of type class. + * * @template A * * @param callable(R): A $mapper @@ -57,7 +63,7 @@ final public static function lift(callable $callable): callable /** * Takes any `iterable>` and sequence it into `self>`. - * If any `self` is "empty", the result is "short circuited". + * If any `self` is "empty", the result is "empty" as well. * * @template A * diff --git a/src/Bonami/Collection/Monad1.php b/src/Bonami/Collection/Monad1.php index c67977b..22875b3 100644 --- a/src/Bonami/Collection/Monad1.php +++ b/src/Bonami/Collection/Monad1.php @@ -11,6 +11,9 @@ trait Monad1 use Applicative1; /** + * Default implementation of ap, derived from flatMap and map. It can be overridden by concrete + * implementation + * * @template A * @template B * @@ -29,6 +32,8 @@ final public static function ap(self $closure, self $argument): self } /** + * Chain mapper call on Monad + * * @template B * * @phpstan-param callable(T, int): iterable $mapper diff --git a/src/Bonami/Collection/Monad2.php b/src/Bonami/Collection/Monad2.php index e640fa4..d9a05c3 100644 --- a/src/Bonami/Collection/Monad2.php +++ b/src/Bonami/Collection/Monad2.php @@ -14,6 +14,9 @@ trait Monad2 use Applicative2; /** + * Default implementation of ap, derived from flatMap and map. It can be overridden by concrete + * implementation + * * @template A * @template B * @@ -32,6 +35,8 @@ final public static function ap(self $closure, self $argument): self } /** + * Chain mapper call on Monad + * * @template B * * @phpstan-param callable(R, int): iterable $mapper From 1d1bb6b57efa6057f323d0a86db01e647cce269f Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Thu, 6 Jan 2022 16:08:14 +0100 Subject: [PATCH 06/28] [BC] Bump php version to 7.4 --- .github/workflows/main.yml | 4 ++-- Makefile | 8 ++++---- composer.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bd17e66..976a6a9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - php: ['7.3', '7.4', '8.0', '8.1'] + php: ['7.4', '8.0', '8.1'] steps: - name: "Checkout" @@ -45,7 +45,7 @@ jobs: strategy: matrix: - php: ['7.3', '7.4', '8.0', '8.1'] + php: ['7.4', '8.0', '8.1'] steps: - name: "Checkout" diff --git a/Makefile b/Makefile index c9d2afb..b053f73 100644 --- a/Makefile +++ b/Makefile @@ -11,13 +11,13 @@ test: $(MAKE) fmt-check phpstan: - docker run -it --rm -v ${PWD}:/app -w /app php:7.3-cli-alpine php -d error_reporting=-1 -d memory_limit=-1 bin/phpstan --ansi analyse + docker run -it --rm -v ${PWD}:/app -w /app php:7.4-cli-alpine php -d error_reporting=-1 -d memory_limit=-1 bin/phpstan --ansi analyse phpunit: - docker run -it --rm -v ${PWD}:/app -w /app php:7.3-cli-alpine php -d error_reporting=-1 bin/phpunit --colors=always -c phpunit.xml + docker run -it --rm -v ${PWD}:/app -w /app php:7.4-cli-alpine php -d error_reporting=-1 bin/phpunit --colors=always -c phpunit.xml fmt-check: - docker run -it --rm -v ${PWD}:/app -w /app php:7.3-cli-alpine php bin/phpcs --standard=./ruleset.xml --extensions=php --tab-width=4 -sp ./src ./tests + docker run -it --rm -v ${PWD}:/app -w /app php:7.4-cli-alpine php bin/phpcs --standard=./ruleset.xml --extensions=php --tab-width=4 -sp ./src ./tests fmt: - docker run -it --rm -v ${PWD}:/app -w /app php:7.3-cli-alpine php bin/phpcbf --standard=./ruleset.xml --extensions=php --tab-width=4 -sp ./src ./tests + docker run -it --rm -v ${PWD}:/app -w /app php:7.4-cli-alpine php bin/phpcbf --standard=./ruleset.xml --extensions=php --tab-width=4 -sp ./src ./tests diff --git a/composer.json b/composer.json index 4e39c55..9b67094 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": ">=7.3|^8.0", + "php": ">=7.4|^8.0", "ext-json": "*" }, "suggest": { From fb37d0326d520c4e75d3a33275ea4429b65e9399 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Thu, 6 Jan 2022 16:08:41 +0100 Subject: [PATCH 07/28] Disable check for arrow function Becuase we are on 7.4 as min version, yay --- ruleset.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/ruleset.xml b/ruleset.xml index a2d33bc..21a8318 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -63,7 +63,6 @@ - From 9766998456934ebc4647c906aad4dac3f28673de Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Thu, 6 Jan 2022 16:09:16 +0100 Subject: [PATCH 08/28] Disable 120 chars for comments To fit long php doc types, namely for thouse complex phpstan types --- ruleset.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ruleset.xml b/ruleset.xml index 21a8318..a2debc0 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -4,6 +4,14 @@ + + + + + + + + From bd8ef5f50c8d085b9cf5f36a7cf2b0211eec870a Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Thu, 6 Jan 2022 16:09:59 +0100 Subject: [PATCH 09/28] Support lifting with up to 30 fixed arguments This allows quite good type safety (it check passed callable for number of arguments and creates well typed callable in return) --- src/Bonami/Collection/Applicative1.php | 885 +++++++++++++++++++++++++ src/Bonami/Collection/Applicative2.php | 885 +++++++++++++++++++++++++ tests/Bonami/Collection/EitherTest.php | 13 + tests/Bonami/Collection/OptionTest.php | 9 + 4 files changed, 1792 insertions(+) diff --git a/src/Bonami/Collection/Applicative1.php b/src/Bonami/Collection/Applicative1.php index 706faab..bdb8bbc 100644 --- a/src/Bonami/Collection/Applicative1.php +++ b/src/Bonami/Collection/Applicative1.php @@ -58,6 +58,891 @@ final public static function lift(callable $callable): callable }; } + /** + * Upgrades callable with 1 argument to accept and return `self` as arguments. + * + * @template I1 + * @template O + * + * @phpstan-param callable(I1): O $callable + * + * @phpstan-return callable(self): self + */ + final public static function lift1(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 2 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template O + * + * @phpstan-param callable(I1, I2): O $callable + * + * @phpstan-return callable(self, self): self + */ + final public static function lift2(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 3 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template O + * + * @phpstan-param callable(I1, I2, I3): O $callable + * + * @phpstan-return callable(self, self, self): self + */ + final public static function lift3(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 4 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4): O $callable + * + * @phpstan-return callable(self, self, self, self): self + */ + final public static function lift4(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 5 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5): O $callable + * + * @phpstan-return callable(self, self, self, self, self): self + */ + final public static function lift5(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 6 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self): self + */ + final public static function lift6(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 7 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self): self + */ + final public static function lift7(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 8 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self): self + */ + final public static function lift8(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 9 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self): self + */ + final public static function lift9(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 10 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift10(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 11 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift11(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 12 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift12(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 13 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift13(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 14 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift14(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 15 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift15(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 16 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift16(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 17 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift17(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 18 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift18(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 19 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift19(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 20 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift20(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 21 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift21(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 22 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift22(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 23 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift23(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 24 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift24(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 25 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift25(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 26 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template I26 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift26(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 27 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template I26 + * @template I27 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift27(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 28 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template I26 + * @template I27 + * @template I28 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift28(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 29 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template I26 + * @template I27 + * @template I28 + * @template I29 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift29(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 30 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template I26 + * @template I27 + * @template I28 + * @template I29 + * @template I30 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift30(callable $callable): callable + { + return self::lift($callable); + } + /** * Takes any `iterable>` and sequence it into `self>`. If any `self` is "empty", the result is * "empty" as well. diff --git a/src/Bonami/Collection/Applicative2.php b/src/Bonami/Collection/Applicative2.php index d685da2..37afd0d 100644 --- a/src/Bonami/Collection/Applicative2.php +++ b/src/Bonami/Collection/Applicative2.php @@ -61,6 +61,891 @@ final public static function lift(callable $callable): callable }; } + /** + * Upgrades callable with 1 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template O + * + * @phpstan-param callable(I1): O $callable + * + * @phpstan-return callable(self): self + */ + final public static function lift1(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 2 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template O + * + * @phpstan-param callable(I1, I2): O $callable + * + * @phpstan-return callable(self, self): self + */ + final public static function lift2(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 3 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template O + * + * @phpstan-param callable(I1, I2, I3): O $callable + * + * @phpstan-return callable(self, self, self): self + */ + final public static function lift3(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 4 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4): O $callable + * + * @phpstan-return callable(self, self, self, self): self + */ + final public static function lift4(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 5 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5): O $callable + * + * @phpstan-return callable(self, self, self, self, self): self + */ + final public static function lift5(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 6 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self): self + */ + final public static function lift6(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 7 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self): self + */ + final public static function lift7(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 8 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self): self + */ + final public static function lift8(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 9 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self): self + */ + final public static function lift9(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 10 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift10(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 11 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift11(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 12 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift12(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 13 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift13(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 14 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift14(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 15 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift15(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 16 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift16(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 17 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift17(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 18 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift18(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 19 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift19(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 20 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift20(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 21 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift21(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 22 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift22(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 23 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift23(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 24 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift24(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 25 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift25(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 26 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template I26 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift26(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 27 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template I26 + * @template I27 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift27(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 28 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template I26 + * @template I27 + * @template I28 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift28(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 29 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template I26 + * @template I27 + * @template I28 + * @template I29 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift29(callable $callable): callable + { + return self::lift($callable); + } + + /** + * Upgrades callable with 30 arguments to accept and return `self` as arguments. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template I26 + * @template I27 + * @template I28 + * @template I29 + * @template I30 + * @template O + * + * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30): O $callable + * + * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + */ + final public static function lift30(callable $callable): callable + { + return self::lift($callable); + } + /** * Takes any `iterable>` and sequence it into `self>`. * If any `self` is "empty", the result is "empty" as well. diff --git a/tests/Bonami/Collection/EitherTest.php b/tests/Bonami/Collection/EitherTest.php index 4c8c7cb..5b74a3e 100644 --- a/tests/Bonami/Collection/EitherTest.php +++ b/tests/Bonami/Collection/EitherTest.php @@ -43,6 +43,19 @@ public function testLift(): void ); } + public function testLiftN(): void + { + self::assertEquals(Either::right(42), Either::lift1(static fn (int $a): int => $a)(Either::right(42))); + self::assertEquals( + Either::right(708), + Either::lift2(static fn (int $a, int $b): int => $a + $b)(Either::right(42), Either::right(666)) + ); + self::assertEquals( + Either::left("fail"), + Either::lift2(static fn (int $a, int $b): int => $a + $b)(Either::right(42), Either::left("fail")) + ); + } + public function testMap(): void { $greeter = static function (string $s): string { diff --git a/tests/Bonami/Collection/OptionTest.php b/tests/Bonami/Collection/OptionTest.php index cd60c02..be680ef 100644 --- a/tests/Bonami/Collection/OptionTest.php +++ b/tests/Bonami/Collection/OptionTest.php @@ -51,6 +51,15 @@ public function testLift(): void ); } + public function testLiftN(): void + { + self::assertEquals(Option::some(42), Option::lift1(static fn (int $a): int => $a)(Option::some(42))); + self::assertEquals( + Option::some(708), + Option::lift2(static fn (int $a, int $b): int => $a + $b)(Option::some(42), Option::some(666)) + ); + } + public function testMap(): void { $mapper = static function (string $s): string { From e3d01114cfb94d085b9dab5b0c253945ae296b3f Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Thu, 6 Jan 2022 20:25:34 +0100 Subject: [PATCH 10/28] Support currying with up to 30 fixed arguments --- src/Bonami/Collection/CurriedFunction.php | 994 +++++++++++++++++++++- 1 file changed, 985 insertions(+), 9 deletions(-) diff --git a/src/Bonami/Collection/CurriedFunction.php b/src/Bonami/Collection/CurriedFunction.php index 8fd5aec..3528801 100644 --- a/src/Bonami/Collection/CurriedFunction.php +++ b/src/Bonami/Collection/CurriedFunction.php @@ -61,13 +61,38 @@ public static function of(callable $callable): self } /** - * @template A - * @template B + * Converts function with 1 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template Z + * + * @param callable(I1): Z $callable + * + * @return self + */ + public static function curry1(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 1); + } + + /** + * Converts function with 2 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 * @template Z * - * @param callable(A, B): Z $callable + * @param callable(I1, I2): Z $callable * - * @return self> + * @return self> */ public static function curry2(callable $callable): self { @@ -75,20 +100,971 @@ public static function curry2(callable $callable): self } /** - * @template A - * @template B - * @template C + * Converts function with 3 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 * @template Z * - * @param callable(A, B, C): Z $callable + * @param callable(I1, I2, I3): Z $callable * - * @return self>> + * @return self>> */ public static function curry3(callable $callable): self { return $callable instanceof self ? $callable : new self($callable, 3); } + /** + * Converts function with 4 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template Z + * + * @param callable(I1, I2, I3, I4): Z $callable + * + * @return self>>> + */ + public static function curry4(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 4); + } + + /** + * Converts function with 5 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5): Z $callable + * + * @return self>>>> + */ + public static function curry5(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 5); + } + + /** + * Converts function with 6 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6): Z $callable + * + * @return self>>>>> + */ + public static function curry6(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 6); + } + + /** + * Converts function with 7 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7): Z $callable + * + * @return self>>>>>> + */ + public static function curry7(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 7); + } + + /** + * Converts function with 8 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8): Z $callable + * + * @return self>>>>>>> + */ + public static function curry8(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 8); + } + + /** + * Converts function with 9 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9): Z $callable + * + * @return self>>>>>>>> + */ + public static function curry9(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 9); + } + + /** + * Converts function with 10 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10): Z $callable + * + * @return self>>>>>>>>> + */ + public static function curry10(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 10); + } + + /** + * Converts function with 11 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11): Z $callable + * + * @return self>>>>>>>>>> + */ + public static function curry11(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 11); + } + + /** + * Converts function with 12 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12): Z $callable + * + * @return self>>>>>>>>>>> + */ + public static function curry12(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 12); + } + + /** + * Converts function with 13 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13): Z $callable + * + * @return self>>>>>>>>>>>> + */ + public static function curry13(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 13); + } + + /** + * Converts function with 14 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14): Z $callable + * + * @return self>>>>>>>>>>>>> + */ + public static function curry14(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 14); + } + + /** + * Converts function with 15 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15): Z $callable + * + * @return self>>>>>>>>>>>>>> + */ + public static function curry15(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 15); + } + + /** + * Converts function with 16 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16): Z $callable + * + * @return self>>>>>>>>>>>>>>> + */ + public static function curry16(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 16); + } + + /** + * Converts function with 17 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17): Z $callable + * + * @return self>>>>>>>>>>>>>>>> + */ + public static function curry17(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 17); + } + + /** + * Converts function with 18 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18): Z $callable + * + * @return self>>>>>>>>>>>>>>>>> + */ + public static function curry18(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 18); + } + + /** + * Converts function with 19 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19): Z $callable + * + * @return self>>>>>>>>>>>>>>>>>> + */ + public static function curry19(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 19); + } + + /** + * Converts function with 20 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20): Z $callable + * + * @return self>>>>>>>>>>>>>>>>>>> + */ + public static function curry20(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 20); + } + + /** + * Converts function with 21 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21): Z $callable + * + * @return self>>>>>>>>>>>>>>>>>>>> + */ + public static function curry21(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 21); + } + + /** + * Converts function with 22 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22): Z $callable + * + * @return self>>>>>>>>>>>>>>>>>>>>> + */ + public static function curry22(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 22); + } + + /** + * Converts function with 23 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23): Z $callable + * + * @return self>>>>>>>>>>>>>>>>>>>>>> + */ + public static function curry23(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 23); + } + + /** + * Converts function with 24 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24): Z $callable + * + * @return self>>>>>>>>>>>>>>>>>>>>>>> + */ + public static function curry24(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 24); + } + + /** + * Converts function with 25 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25): Z $callable + * + * @return self>>>>>>>>>>>>>>>>>>>>>>>> + */ + public static function curry25(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 25); + } + + /** + * Converts function with 26 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template I26 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26): Z $callable + * + * @return self>>>>>>>>>>>>>>>>>>>>>>>>> + */ + public static function curry26(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 26); + } + + /** + * Converts function with 27 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template I26 + * @template I27 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27): Z $callable + * + * @return self>>>>>>>>>>>>>>>>>>>>>>>>>> + */ + public static function curry27(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 27); + } + + /** + * Converts function with 28 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template I26 + * @template I27 + * @template I28 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28): Z $callable + * + * @return self>>>>>>>>>>>>>>>>>>>>>>>>>>> + */ + public static function curry28(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 28); + } + + /** + * Converts function with 29 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template I26 + * @template I27 + * @template I28 + * @template I29 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29): Z $callable + * + * @return self>>>>>>>>>>>>>>>>>>>>>>>>>>>> + */ + public static function curry29(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 29); + } + + /** + * Converts function with 30 arguments to curried version, which accepts one argument + * at time and returns another function that accepts another argument up to last one, + * then it returns the actual result. + * + * That way we can do partial function application, which allows some cool FP usages. + * + * @template I1 + * @template I2 + * @template I3 + * @template I4 + * @template I5 + * @template I6 + * @template I7 + * @template I8 + * @template I9 + * @template I10 + * @template I11 + * @template I12 + * @template I13 + * @template I14 + * @template I15 + * @template I16 + * @template I17 + * @template I18 + * @template I19 + * @template I20 + * @template I21 + * @template I22 + * @template I23 + * @template I24 + * @template I25 + * @template I26 + * @template I27 + * @template I28 + * @template I29 + * @template I30 + * @template Z + * + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30): Z $callable + * + * @return self>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + */ + public static function curry30(callable $callable): self + { + return $callable instanceof self ? $callable : new self($callable, 30); + } + /** * Mapping over function is equivalent of composing functions * From b9c669abc1f4c77f0a9b67c3cb16b2ce73a6a847 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Thu, 13 Jan 2022 16:34:20 +0100 Subject: [PATCH 11/28] Remove phpstan prefixes They are no longer needed --- src/Bonami/Collection/Applicative1.php | 142 +++++------ src/Bonami/Collection/Applicative2.php | 140 +++++------ src/Bonami/Collection/ArrayList.php | 228 +++++++++--------- src/Bonami/Collection/CurriedFunction.php | 10 +- src/Bonami/Collection/Either.php | 94 ++++---- src/Bonami/Collection/Enum.php | 32 +-- src/Bonami/Collection/EnumList.php | 6 +- src/Bonami/Collection/Hash/IHashable.php | 2 +- src/Bonami/Collection/LazyList.php | 150 ++++++------ src/Bonami/Collection/Map.php | 160 ++++++------ src/Bonami/Collection/Monad1.php | 4 +- src/Bonami/Collection/Monad2.php | 4 +- .../Collection/Monoid/DoubleProductMonoid.php | 2 +- .../Collection/Monoid/DoubleSumMonoid.php | 2 +- .../Collection/Monoid/IntProductMonoid.php | 2 +- src/Bonami/Collection/Monoid/IntSumMonoid.php | 2 +- src/Bonami/Collection/Monoid/Monoid.php | 8 +- src/Bonami/Collection/Monoid/OptionMonoid.php | 14 +- src/Bonami/Collection/Monoid/StringMonoid.php | 2 +- src/Bonami/Collection/Mutable/Map.php | 12 +- src/Bonami/Collection/Option.php | 102 ++++---- src/Bonami/Collection/TrySafe.php | 116 ++++----- src/Bonami/Collection/helpers.php | 8 +- 23 files changed, 621 insertions(+), 621 deletions(-) diff --git a/src/Bonami/Collection/Applicative1.php b/src/Bonami/Collection/Applicative1.php index bdb8bbc..658183d 100644 --- a/src/Bonami/Collection/Applicative1.php +++ b/src/Bonami/Collection/Applicative1.php @@ -12,9 +12,9 @@ trait Applicative1 * * @template A * - * @phpstan-param A $value + * @param A $value * - * @phpstan-return static + * @return static */ abstract public static function pure($value); @@ -36,18 +36,18 @@ abstract public static function ap(self $closure, self $argument): self; * * @template A * - * @phpstan-param callable(T): A $mapper + * @param callable(T): A $mapper * - * @phpstan-return self + * @return self */ abstract public function map(callable $mapper): self; /** * Upgrades callable to accept and return `self` as arguments. * - * @phpstan-param callable $callable + * @param callable $callable * - * @phpstan-return callable + * @return callable */ final public static function lift(callable $callable): callable { @@ -64,9 +64,9 @@ final public static function lift(callable $callable): callable * @template I1 * @template O * - * @phpstan-param callable(I1): O $callable + * @param callable(I1): O $callable * - * @phpstan-return callable(self): self + * @return callable(self): self */ final public static function lift1(callable $callable): callable { @@ -80,9 +80,9 @@ final public static function lift1(callable $callable): callable * @template I2 * @template O * - * @phpstan-param callable(I1, I2): O $callable + * @param callable(I1, I2): O $callable * - * @phpstan-return callable(self, self): self + * @return callable(self, self): self */ final public static function lift2(callable $callable): callable { @@ -97,9 +97,9 @@ final public static function lift2(callable $callable): callable * @template I3 * @template O * - * @phpstan-param callable(I1, I2, I3): O $callable + * @param callable(I1, I2, I3): O $callable * - * @phpstan-return callable(self, self, self): self + * @return callable(self, self, self): self */ final public static function lift3(callable $callable): callable { @@ -115,9 +115,9 @@ final public static function lift3(callable $callable): callable * @template I4 * @template O * - * @phpstan-param callable(I1, I2, I3, I4): O $callable + * @param callable(I1, I2, I3, I4): O $callable * - * @phpstan-return callable(self, self, self, self): self + * @return callable(self, self, self, self): self */ final public static function lift4(callable $callable): callable { @@ -134,9 +134,9 @@ final public static function lift4(callable $callable): callable * @template I5 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5): O $callable + * @param callable(I1, I2, I3, I4, I5): O $callable * - * @phpstan-return callable(self, self, self, self, self): self + * @return callable(self, self, self, self, self): self */ final public static function lift5(callable $callable): callable { @@ -154,9 +154,9 @@ final public static function lift5(callable $callable): callable * @template I6 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6): O $callable + * @param callable(I1, I2, I3, I4, I5, I6): O $callable * - * @phpstan-return callable(self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self): self */ final public static function lift6(callable $callable): callable { @@ -175,9 +175,9 @@ final public static function lift6(callable $callable): callable * @template I7 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self): self */ final public static function lift7(callable $callable): callable { @@ -197,9 +197,9 @@ final public static function lift7(callable $callable): callable * @template I8 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self): self */ final public static function lift8(callable $callable): callable { @@ -220,9 +220,9 @@ final public static function lift8(callable $callable): callable * @template I9 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self): self */ final public static function lift9(callable $callable): callable { @@ -244,9 +244,9 @@ final public static function lift9(callable $callable): callable * @template I10 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self): self */ final public static function lift10(callable $callable): callable { @@ -269,9 +269,9 @@ final public static function lift10(callable $callable): callable * @template I11 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift11(callable $callable): callable { @@ -295,9 +295,9 @@ final public static function lift11(callable $callable): callable * @template I12 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift12(callable $callable): callable { @@ -322,9 +322,9 @@ final public static function lift12(callable $callable): callable * @template I13 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift13(callable $callable): callable { @@ -350,9 +350,9 @@ final public static function lift13(callable $callable): callable * @template I14 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift14(callable $callable): callable { @@ -379,9 +379,9 @@ final public static function lift14(callable $callable): callable * @template I15 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift15(callable $callable): callable { @@ -409,9 +409,9 @@ final public static function lift15(callable $callable): callable * @template I16 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift16(callable $callable): callable { @@ -440,9 +440,9 @@ final public static function lift16(callable $callable): callable * @template I17 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift17(callable $callable): callable { @@ -472,9 +472,9 @@ final public static function lift17(callable $callable): callable * @template I18 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift18(callable $callable): callable { @@ -505,9 +505,9 @@ final public static function lift18(callable $callable): callable * @template I19 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift19(callable $callable): callable { @@ -539,9 +539,9 @@ final public static function lift19(callable $callable): callable * @template I20 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift20(callable $callable): callable { @@ -574,9 +574,9 @@ final public static function lift20(callable $callable): callable * @template I21 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift21(callable $callable): callable { @@ -610,9 +610,9 @@ final public static function lift21(callable $callable): callable * @template I22 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift22(callable $callable): callable { @@ -647,9 +647,9 @@ final public static function lift22(callable $callable): callable * @template I23 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift23(callable $callable): callable { @@ -685,9 +685,9 @@ final public static function lift23(callable $callable): callable * @template I24 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift24(callable $callable): callable { @@ -724,9 +724,9 @@ final public static function lift24(callable $callable): callable * @template I25 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift25(callable $callable): callable { @@ -764,9 +764,9 @@ final public static function lift25(callable $callable): callable * @template I26 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift26(callable $callable): callable { @@ -805,9 +805,9 @@ final public static function lift26(callable $callable): callable * @template I27 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift27(callable $callable): callable { @@ -847,9 +847,9 @@ final public static function lift27(callable $callable): callable * @template I28 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift28(callable $callable): callable { @@ -890,9 +890,9 @@ final public static function lift28(callable $callable): callable * @template I29 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift29(callable $callable): callable { @@ -934,9 +934,9 @@ final public static function lift29(callable $callable): callable * @template I30 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift30(callable $callable): callable { @@ -949,9 +949,9 @@ final public static function lift30(callable $callable): callable * * @template A * - * @phpstan-param iterable> $iterable + * @param iterable> $iterable * - * @phpstan-return self> + * @return self> */ final public static function sequence(iterable $iterable): self { @@ -968,10 +968,10 @@ final public static function sequence(iterable $iterable): self * @template A * @template B * - * @phpstan-param iterable $iterable - * @phpstan-param callable(A): self $mapperToApplicative + * @param iterable $iterable + * @param callable(A): self $mapperToApplicative * - * @phpstan-return self> + * @return self> */ final public static function traverse(iterable $iterable, callable $mapperToApplicative): self { diff --git a/src/Bonami/Collection/Applicative2.php b/src/Bonami/Collection/Applicative2.php index 37afd0d..555dd0d 100644 --- a/src/Bonami/Collection/Applicative2.php +++ b/src/Bonami/Collection/Applicative2.php @@ -15,9 +15,9 @@ trait Applicative2 * * @template A * - * @phpstan-param A $value + * @param A $value * - * @phpstan-return static + * @return static */ abstract public static function pure($value); @@ -41,16 +41,16 @@ abstract public static function ap(self $closure, self $argument): self; * * @param callable(R): A $mapper * - * @phpstan-return self + * @return self */ abstract public function map(callable $mapper): self; /** * Upgrades callable to accept and return `self` as arguments. * - * @phpstan-param callable $callable + * @param callable $callable * - * @phpstan-return callable + * @return callable */ final public static function lift(callable $callable): callable { @@ -67,9 +67,9 @@ final public static function lift(callable $callable): callable * @template I1 * @template O * - * @phpstan-param callable(I1): O $callable + * @param callable(I1): O $callable * - * @phpstan-return callable(self): self + * @return callable(self): self */ final public static function lift1(callable $callable): callable { @@ -83,9 +83,9 @@ final public static function lift1(callable $callable): callable * @template I2 * @template O * - * @phpstan-param callable(I1, I2): O $callable + * @param callable(I1, I2): O $callable * - * @phpstan-return callable(self, self): self + * @return callable(self, self): self */ final public static function lift2(callable $callable): callable { @@ -100,9 +100,9 @@ final public static function lift2(callable $callable): callable * @template I3 * @template O * - * @phpstan-param callable(I1, I2, I3): O $callable + * @param callable(I1, I2, I3): O $callable * - * @phpstan-return callable(self, self, self): self + * @return callable(self, self, self): self */ final public static function lift3(callable $callable): callable { @@ -118,9 +118,9 @@ final public static function lift3(callable $callable): callable * @template I4 * @template O * - * @phpstan-param callable(I1, I2, I3, I4): O $callable + * @param callable(I1, I2, I3, I4): O $callable * - * @phpstan-return callable(self, self, self, self): self + * @return callable(self, self, self, self): self */ final public static function lift4(callable $callable): callable { @@ -137,9 +137,9 @@ final public static function lift4(callable $callable): callable * @template I5 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5): O $callable + * @param callable(I1, I2, I3, I4, I5): O $callable * - * @phpstan-return callable(self, self, self, self, self): self + * @return callable(self, self, self, self, self): self */ final public static function lift5(callable $callable): callable { @@ -157,9 +157,9 @@ final public static function lift5(callable $callable): callable * @template I6 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6): O $callable + * @param callable(I1, I2, I3, I4, I5, I6): O $callable * - * @phpstan-return callable(self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self): self */ final public static function lift6(callable $callable): callable { @@ -178,9 +178,9 @@ final public static function lift6(callable $callable): callable * @template I7 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self): self */ final public static function lift7(callable $callable): callable { @@ -200,9 +200,9 @@ final public static function lift7(callable $callable): callable * @template I8 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self): self */ final public static function lift8(callable $callable): callable { @@ -223,9 +223,9 @@ final public static function lift8(callable $callable): callable * @template I9 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self): self */ final public static function lift9(callable $callable): callable { @@ -247,9 +247,9 @@ final public static function lift9(callable $callable): callable * @template I10 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self): self */ final public static function lift10(callable $callable): callable { @@ -272,9 +272,9 @@ final public static function lift10(callable $callable): callable * @template I11 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift11(callable $callable): callable { @@ -298,9 +298,9 @@ final public static function lift11(callable $callable): callable * @template I12 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift12(callable $callable): callable { @@ -325,9 +325,9 @@ final public static function lift12(callable $callable): callable * @template I13 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift13(callable $callable): callable { @@ -353,9 +353,9 @@ final public static function lift13(callable $callable): callable * @template I14 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift14(callable $callable): callable { @@ -382,9 +382,9 @@ final public static function lift14(callable $callable): callable * @template I15 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift15(callable $callable): callable { @@ -412,9 +412,9 @@ final public static function lift15(callable $callable): callable * @template I16 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift16(callable $callable): callable { @@ -443,9 +443,9 @@ final public static function lift16(callable $callable): callable * @template I17 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift17(callable $callable): callable { @@ -475,9 +475,9 @@ final public static function lift17(callable $callable): callable * @template I18 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift18(callable $callable): callable { @@ -508,9 +508,9 @@ final public static function lift18(callable $callable): callable * @template I19 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift19(callable $callable): callable { @@ -542,9 +542,9 @@ final public static function lift19(callable $callable): callable * @template I20 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift20(callable $callable): callable { @@ -577,9 +577,9 @@ final public static function lift20(callable $callable): callable * @template I21 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift21(callable $callable): callable { @@ -613,9 +613,9 @@ final public static function lift21(callable $callable): callable * @template I22 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift22(callable $callable): callable { @@ -650,9 +650,9 @@ final public static function lift22(callable $callable): callable * @template I23 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift23(callable $callable): callable { @@ -688,9 +688,9 @@ final public static function lift23(callable $callable): callable * @template I24 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift24(callable $callable): callable { @@ -727,9 +727,9 @@ final public static function lift24(callable $callable): callable * @template I25 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift25(callable $callable): callable { @@ -767,9 +767,9 @@ final public static function lift25(callable $callable): callable * @template I26 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift26(callable $callable): callable { @@ -808,9 +808,9 @@ final public static function lift26(callable $callable): callable * @template I27 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift27(callable $callable): callable { @@ -850,9 +850,9 @@ final public static function lift27(callable $callable): callable * @template I28 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift28(callable $callable): callable { @@ -893,9 +893,9 @@ final public static function lift28(callable $callable): callable * @template I29 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift29(callable $callable): callable { @@ -937,9 +937,9 @@ final public static function lift29(callable $callable): callable * @template I30 * @template O * - * @phpstan-param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30): O $callable + * @param callable(I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30): O $callable * - * @phpstan-return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self + * @return callable(self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self, self): self */ final public static function lift30(callable $callable): callable { @@ -952,9 +952,9 @@ final public static function lift30(callable $callable): callable * * @template A * - * @phpstan-param iterable> $iterable + * @param iterable> $iterable * - * @phpstan-return self> + * @return self> */ final public static function sequence(iterable $iterable): self { @@ -971,10 +971,10 @@ final public static function sequence(iterable $iterable): self * @template A * @template B * - * @phpstan-param iterable $iterable - * @phpstan-param callable(A): self $mapperToApplicative + * @param iterable $iterable + * @param callable(A): self $mapperToApplicative * - * @phpstan-return self> + * @return self> */ final public static function traverse(iterable $iterable, callable $mapperToApplicative): self { diff --git a/src/Bonami/Collection/ArrayList.php b/src/Bonami/Collection/ArrayList.php index 7e1baac..a4585a7 100644 --- a/src/Bonami/Collection/ArrayList.php +++ b/src/Bonami/Collection/ArrayList.php @@ -39,17 +39,17 @@ /** * @template T * - * @phpstan-implements IteratorAggregate + * @implements IteratorAggregate */ class ArrayList implements Countable, IteratorAggregate, JsonSerializable { /** @use Monad1 */ use Monad1; - /** @phpstan-var array */ + /** @var array */ protected $items; - /** @phpstan-param array $items */ + /** @param array $items */ final public function __construct(array $items) { $this->items = $items; @@ -60,7 +60,7 @@ final public function __construct(array $items) * * Complexity: o(1) * - * @phpstan-return static + * @return static */ public static function fromEmpty() { @@ -74,9 +74,9 @@ public static function fromEmpty() * * @template V * - * @phpstan-param V ...$item - with any number of occurences + * @param V ...$item - with any number of occurences * - * @phpstan-return static + * @return static */ public static function of(...$item) { @@ -90,9 +90,9 @@ public static function of(...$item) * * @template V * - * @phpstan-param V $item + * @param V $item * - * @phpstan-return static + * @return static */ public static function pure($item) { @@ -106,10 +106,10 @@ public static function pure($item) * * @template V * - * @phpstan-param V $item - an item to be filled - * @phpstan-param int $size - size of desired ArrayList with filled $item as each element + * @param V $item - an item to be filled + * @param int $size - size of desired ArrayList with filled $item as each element * - * @phpstan-return static + * @return static */ public static function fill($item, int $size) { @@ -123,13 +123,13 @@ public static function fill($item, int $size) * * @see LazyList::range() - for initializing range lazily * - * @phpstan-param int $min - a minimal (starting) value of range - * @phpstan-param int $max - a maximum value of range - it may or maybe not be included + * @param int $min - a minimal (starting) value of range + * @param int $max - a maximum value of range - it may or maybe not be included * as last element if the step does not step * over it. - * @phpstan-param int $step - a size of step between each item of range + * @param int $step - a size of step between each item of range * - * @phpstan-return self + * @return self */ public static function range(int $min, int $max, int $step = 1): self { @@ -144,10 +144,10 @@ public static function range(int $min, int $max, int $step = 1): self * * Complexity: o(n) - where n is length of string * - * @phpstan-param string $delimiter - a delimiter to be used for spliting - * @phpstan-param string $string - a string to be exploded + * @param string $delimiter - a delimiter to be used for spliting + * @param string $string - a string to be exploded * - * @phpstan-return self + * @return self */ public static function explode(string $delimiter, string $string): self { @@ -168,9 +168,9 @@ public static function explode(string $delimiter, string $string): self * * @template V * - * @phpstan-param iterable $iterable + * @param iterable $iterable * - * @phpstan-return static + * @return static */ public static function fromIterable(iterable $iterable) { @@ -189,9 +189,9 @@ public static function fromIterable(iterable $iterable) * * @template V * - * @phpstan-param iterable $iterable + * @param iterable $iterable * - * @phpstan-return array + * @return array */ private static function convertIterableToArray(iterable $iterable): array { @@ -215,7 +215,7 @@ private static function convertIterableToArray(iterable $iterable): array * * Complexity: o(1) - Retriving the iterator itself is constant. Iterating over it is of course o(n) * - * @phpstan-return Iterator + * @return Iterator */ public function getIterator(): Iterator { @@ -227,7 +227,7 @@ public function getIterator(): Iterator * * Complexity: o(1) * - * @phpstan-return int + * @return int */ public function count(): int { @@ -241,7 +241,7 @@ public function count(): int * * @see isNotEmpty * - * @phpstan-return bool + * @return bool */ public function isEmpty(): bool { @@ -255,7 +255,7 @@ public function isEmpty(): bool * * @see isEmpty * - * @phpstan-return bool + * @return bool */ public function isNotEmpty(): bool { @@ -270,9 +270,9 @@ public function isNotEmpty(): bool * @see getUnsafe - when you are 100 % sure, that key is set * @see getOrElse - for unboxing value directly with alternative value when value is not set * - * @phpstan-param int $key + * @param int $key * - * @phpstan-return Option + * @return Option */ public function get(int $key): Option { @@ -291,10 +291,10 @@ public function get(int $key): Option * * @template E * - * @phpstan-param int $key - * @phpstan-param E $else + * @param int $key + * @param E $else * - * @phpstan-return T|E + * @return T|E */ public function getOrElse(int $key, $else) { @@ -309,11 +309,11 @@ public function getOrElse(int $key, $else) * @see get - for getting Option instead of unboxing it directly * @see getOrElse - for unboxing value directly with alternative value when value is not set * - * @phpstan-param int $key + * @param int $key * * @throws OutOfBoundsException * - * @phpstan-return T + * @return T */ public function getUnsafe(int $key) { @@ -332,9 +332,9 @@ public function getUnsafe(int $key) * * @template B * - * @phpstan-param callable(T, int): B $mapper + * @param callable(T, int): B $mapper * - * @phpstan-return self + * @return self */ public function map(callable $mapper): self { @@ -355,9 +355,9 @@ public function map(callable $mapper): self * * @template B * - * @phpstan-param callable(T, int): iterable $mapper + * @param callable(T, int): iterable $mapper * - * @phpstan-return self + * @return self */ public function flatMap(callable $mapper): self { @@ -375,7 +375,7 @@ public function flatMap(callable $mapper): self * * @see flatMap * - * @phpstan-return self + * @return self */ public function flatten(): self { @@ -405,9 +405,9 @@ public function flatten(): self * * @template B * - * @phpstan-param callable(T, int): B $mapper + * @param callable(T, int): B $mapper * - * @phpstan-return self + * @return self */ public function uniqueMap(callable $mapper): self { @@ -441,9 +441,9 @@ public function uniqueMap(callable $mapper): self * * @template B * - * @phpstan-param callable(T, int): B $discriminator + * @param callable(T, int): B $discriminator * - * @phpstan-return static + * @return static */ public function uniqueBy(callable $discriminator) { @@ -474,7 +474,7 @@ public function uniqueBy(callable $discriminator) * @see uniqueMap * @see IHashable::hashCode * - * @phpstan-return static + * @return static */ public function unique() { @@ -495,9 +495,9 @@ public function unique() * @see concat - to append items from iterable without deduplicating * @see unique - for more info about how deduplication work * - * @phpstan-param iterable $list + * @param iterable $list * - * @phpstan-return static + * @return static */ public function union(iterable $list) { @@ -509,9 +509,9 @@ public function union(iterable $list) * * Complexity: o(n) * - * @phpstan-param callable(T, int): bool $predicate + * @param callable(T, int): bool $predicate * - * @phpstan-return static + * @return static */ public function filter(callable $predicate) { @@ -526,9 +526,9 @@ public function filter(callable $predicate) * @see exists - if you just need to check if something matches by predicate * @see findKey - if you need to get key by predicate * - * @phpstan-param callable(T, int): bool $predicate + * @param callable(T, int): bool $predicate * - * @phpstan-return Option + * @return Option */ public function find(callable $predicate): Option { @@ -548,9 +548,9 @@ public function find(callable $predicate): Option * @see exists - if you just need to check if something matches by predicate * @see find - if you need to get item by predicate * - * @phpstan-param callable(T, int): bool $predicate + * @param callable(T, int): bool $predicate * - * @phpstan-return Option + * @return Option */ public function findKey(callable $predicate): Option { @@ -571,9 +571,9 @@ public function findKey(callable $predicate): Option * @see contains - if you need to check item existence directly without predicate * @see all - if you need to check if ALL items in List satisfy predicate * - * @phpstan-param callable(T, int): bool $predicate + * @param callable(T, int): bool $predicate * - * @phpstan-return bool + * @return bool */ public function exists(callable $predicate): bool { @@ -593,10 +593,10 @@ public function exists(callable $predicate): bool * @see exists - if you need to check if something exists by predicate * @see find - if you need to get item by predicate * - * @phpstan-param T $item - item for lookup - * @phpstan-param bool|null $strictComparison - if true, identity (===) comparison is used, equality otherwise (==) + * @param T $item - item for lookup + * @param bool|null $strictComparison - if true, identity (===) comparison is used, equality otherwise (==) * - * @phpstan-return bool + * @return bool */ public function contains($item, ?bool $strictComparison = true): bool { @@ -611,9 +611,9 @@ public function contains($item, ?bool $strictComparison = true): bool * @see exists - if you need to check if AT LEAST ONE item in List satisfy predicate * @see find - if you need to get item by predicate * - * @phpstan-param callable(T, int): bool $predicate + * @param callable(T, int): bool $predicate * - * @phpstan-return bool + * @return bool */ public function all(callable $predicate): bool { @@ -636,10 +636,10 @@ public function all(callable $predicate): bool * * @see comparator() - a default value for $comparator when ommited * - * @phpstan-param null|callable(T, T): int $comparator - classic comparator returning 1, 0 or -1 + * @param null|callable(T, T): int $comparator - classic comparator returning 1, 0 or -1 * if no comparator is passed, $first <=> $second is used * - * @phpstan-return static + * @return static */ public function sort(?callable $comparator = null) { @@ -655,9 +655,9 @@ public function sort(?callable $comparator = null) * * @template M * - * @phpstan-param callable(T, int): M $indexCallback + * @param callable(T, int): M $indexCallback * - * @phpstan-return Map + * @return Map */ public function index(callable $indexCallback): Map { @@ -671,7 +671,7 @@ public function index(callable $indexCallback): Map * * Complexity: o(1) * - * @phpstan-return array + * @return array */ public function toArray(): array { @@ -685,10 +685,10 @@ public function toArray(): array * * @template R * - * @phpstan-param callable(R, T, int): R $reducer - ($carry: mixed, $item: mixed, $key: int) => mixed - * @phpstan-param R $initialReduction - initial value used as seed for $carry + * @param callable(R, T, int): R $reducer - ($carry: mixed, $item: mixed, $key: int) => mixed + * @param R $initialReduction - initial value used as seed for $carry * - * @phpstan-return R - reduced values. If the list is empty, $initialReduction is directly returned + * @return R - reduced values. If the list is empty, $initialReduction is directly returned */ public function reduce(callable $reducer, $initialReduction) { @@ -704,9 +704,9 @@ public function reduce(callable $reducer, $initialReduction) * * @see sum - for trivial summing * - * @phpstan-param Monoid $monoid + * @param Monoid $monoid * - * @phpstan-return T + * @return T */ public function mfold(Monoid $monoid) { @@ -722,9 +722,9 @@ public function mfold(Monoid $monoid) * * @see mfold - for folding diferent types of items (E.g. classes representing BigNumbers and so on) * - * @phpstan-param callable(T): (int|float) $itemToNumber + * @param callable(T): (int|float) $itemToNumber * - * @phpstan-return int|float + * @return int|float */ public function sum(callable $itemToNumber) { @@ -738,10 +738,10 @@ public function sum(callable $itemToNumber) * * Complexity: o(n) * - * @phpstan-param null|callable(T, T): int $comparator - classic comparator returning 1, 0 or -1 + * @param null|callable(T, T): int $comparator - classic comparator returning 1, 0 or -1 * if no comparator is passed, $first <=> $second is used * - * @phpstan-return Option minimal value wrapped in Option::some or Option::none when list is empty + * @return Option minimal value wrapped in Option::some or Option::none when list is empty */ public function min(?callable $comparator = null): Option { @@ -766,10 +766,10 @@ public function min(?callable $comparator = null): Option * * Complexity: o(n) * - * @phpstan-param null|callable(T, T): int $comparator - classic comparator returning 1, 0 or -1 + * @param null|callable(T, T): int $comparator - classic comparator returning 1, 0 or -1 * if no comparator is passed, $first <=> $second is used * - * @phpstan-return Option minimal value wrapped in Option::some or Option::none when list is empty + * @return Option minimal value wrapped in Option::some or Option::none when list is empty */ public function max(?callable $comparator = null): Option { @@ -794,9 +794,9 @@ public function max(?callable $comparator = null): Option * * Complexity: o(n) * - * @phpstan-param callable(T, int): void $sideEffect + * @param callable(T, int): void $sideEffect * - * @phpstan-return void + * @return void */ public function each(callable $sideEffect): void { @@ -812,9 +812,9 @@ public function each(callable $sideEffect): void * * Complexity: o(n) * - * @phpstan-param callable(T, int): void $sideEffect + * @param callable(T, int): void $sideEffect * - * @phpstan-return static + * @return static */ public function tap(callable $sideEffect) { @@ -830,7 +830,7 @@ public function tap(callable $sideEffect) * * Complexity: o(1) * - * @phpstan-return Option item wrapped with Option::some or Option::none if list is empty + * @return Option item wrapped with Option::some or Option::none if list is empty */ public function head(): Option { @@ -842,7 +842,7 @@ public function head(): Option * * Complexity: o(n) - where n is `$size` * - * @phpstan-return static + * @return static */ public function take(int $size) { @@ -854,11 +854,11 @@ public function take(int $size) * * Complexity: o(n) - where n is size of resulting List * - * @phpstan-param int $offset - from which index the slicing should start - * @phpstan-param int|null $limit - how much items should be taken from offset. + * @param int $offset - from which index the slicing should start + * @param int|null $limit - how much items should be taken from offset. * when nothing is specified, the items are taken until end of List * - * @phpstan-return static + * @return static */ public function slice(int $offset, ?int $limit = null) { @@ -870,7 +870,7 @@ public function slice(int $offset, ?int $limit = null) * * Complexity: o(1) * - * @phpstan-return Option item wrapped with Option::some or Option::none if list is empty + * @return Option item wrapped with Option::some or Option::none if list is empty */ public function last(): Option { @@ -887,7 +887,7 @@ public function last(): Option * * Complexity: o(n) * - * @phpstan-return static + * @return static */ public function withoutNulls() { @@ -908,10 +908,10 @@ public function withoutNulls() * n = number of items in this list * m = number of items to remove. * - * @phpstan-param iterable $itemsToRemove - * @phpstan-param bool|null $strictComparison + * @param iterable $itemsToRemove + * @param bool|null $strictComparison * - * @phpstan-return static + * @return static */ public function minus(iterable $itemsToRemove, ?bool $strictComparison = true) { @@ -924,7 +924,7 @@ public function minus(iterable $itemsToRemove, ?bool $strictComparison = true) } if ($strictComparison) { - /** @phpstan-var array */ + /** @var array */ $pairs = array_map(static function ($item): array { return [$item, true]; }, $itemsToRemoveArray); @@ -948,10 +948,10 @@ static function ($item) use ($itemsToRemoveArray): bool { * * Complexity: o(n) - strict comparison is slightly faster (with same complexity, but less hidden cost) * - * @phpstan-param T $itemToRemove - * @phpstan-param bool|null $strictComparison + * @param T $itemToRemove + * @param bool|null $strictComparison * - * @phpstan-return static + * @return static */ public function minusOne($itemToRemove, ?bool $strictComparison = true) { @@ -973,9 +973,9 @@ public function minusOne($itemToRemove, ?bool $strictComparison = true) * * @template T2 * - * @phpstan-param iterable $itemsToAdd + * @param iterable $itemsToAdd * - * @phpstan-return static + * @return static */ public function concat(iterable $itemsToAdd) { @@ -987,9 +987,9 @@ public function concat(iterable $itemsToAdd) * * Complexity: o(n) * - * @phpstan-param iterable $items + * @param iterable $items * - * @phpstan-return static + * @return static */ public function intersect(iterable $items) { @@ -1006,9 +1006,9 @@ public function intersect(iterable $items) * * @template G * - * @phpstan-param callable(T, int): G $groupBy + * @param callable(T, int): G $groupBy * - * @phpstan-return Map> + * @return Map> */ public function groupBy(callable $groupBy): Map { @@ -1026,9 +1026,9 @@ public function groupBy(callable $groupBy): Map * * Complexity: o(n) * - * @phpstan-param int $size - size of resulting nested List + * @param int $size - size of resulting nested List * - * @phpstan-return self> + * @return self> */ public function chunk(int $size): self { @@ -1055,9 +1055,9 @@ static function ($chunk) { * * @template V * - * @phpstan-param iterable $values + * @param iterable $values * - * @phpstan-return Map + * @return Map */ public function combine(iterable $values): Map { @@ -1076,9 +1076,9 @@ public function combine(iterable $values): Map * * @template B * - * @phpstan-param iterable $iterable + * @param iterable $iterable * - * @phpstan-return self + * @return self */ public function zip(iterable $iterable): self { @@ -1092,9 +1092,9 @@ public function zip(iterable $iterable): self * * @template B * - * @phpstan-param callable(T, int): B $mapper + * @param callable(T, int): B $mapper * - * @phpstan-return Map + * @return Map */ public function zipMap(callable $mapper): Map { @@ -1107,9 +1107,9 @@ public function zipMap(callable $mapper): Map * * Complexity: o(n) * - * @phpstan-param string $glue + * @param string $glue * - * @phpstan-return string + * @return string */ public function join(string $glue): string { @@ -1121,7 +1121,7 @@ public function join(string $glue): string * * Complexity: o(n) * - * @phpstan-return array + * @return array */ public function jsonSerialize(): array { @@ -1133,7 +1133,7 @@ public function jsonSerialize(): array * * Complexity: o(n) * - * @phpstan-return static + * @return static */ public function reverse() { @@ -1148,11 +1148,11 @@ public function reverse() * * Complexity: o(n) * - * @phpstan-return Map + * @return Map */ public function toMap(): Map { - /** @phpstan-var array */ + /** @var array */ $pairs = $this->items; return Map::fromIterable($pairs); } @@ -1172,9 +1172,9 @@ public function lazy(): LazyList * * @internal * - * @phpstan-param T $item + * @param T $item * - * @phpstan-return string + * @return string */ private function itemToString($item): string { diff --git a/src/Bonami/Collection/CurriedFunction.php b/src/Bonami/Collection/CurriedFunction.php index 3528801..6402454 100644 --- a/src/Bonami/Collection/CurriedFunction.php +++ b/src/Bonami/Collection/CurriedFunction.php @@ -24,10 +24,10 @@ final class CurriedFunction protected $numberOfArgs; /** - * @phpstan-param callable $callable - closure to wrap and convert into curried closure - * @phpstan-param int $expectedNumberOfArgs - if ommited, number of arguments is detected + * @param callable $callable - closure to wrap and convert into curried closure + * @param int $expectedNumberOfArgs - if ommited, number of arguments is detected * with slight performance impact - * @phpstan-param array $applied - applied arguments tracked for delayed full aplication of final argument + * @param array $applied - applied arguments tracked for delayed full aplication of final argument */ private function __construct(callable $callable, int $expectedNumberOfArgs, array $applied = []) { @@ -1082,9 +1082,9 @@ public function map(CurriedFunction $callable): CurriedFunction } /** - * @phpstan-param I $arg + * @param I $arg * - * @phpstan-return O + * @return O */ public function __invoke($arg) { diff --git a/src/Bonami/Collection/Either.php b/src/Bonami/Collection/Either.php index 73e4fe0..f343f99 100644 --- a/src/Bonami/Collection/Either.php +++ b/src/Bonami/Collection/Either.php @@ -26,7 +26,7 @@ * @template L * @template R * - * @phpstan-implements IteratorAggregate + * @implements IteratorAggregate */ abstract class Either implements IHashable, IteratorAggregate { @@ -44,7 +44,7 @@ final public static function left($left): self /** @var L */ private $left; - /** @phpstan-param L $left */ + /** @param L $left */ protected function __construct($left) { $this->left = $left; @@ -103,7 +103,7 @@ public function exists(callable $predicate): bool * * @throws ValueIsNotPresentException * - * @phpstan-return L + * @return L */ public function getLeftUnsafe() { @@ -115,7 +115,7 @@ public function getLeftUnsafe() * * @throws ValueIsNotPresentException * - * @phpstan-return R + * @return R */ public function getRightUnsafe() { @@ -130,9 +130,9 @@ public function resolve(callable $handleLeft, callable $handleRight) /** * @template E * - * @phpstan-param E $else + * @param E $else * - * @phpstan-return R|E + * @return R|E */ public function getOrElse($else) { @@ -144,8 +144,8 @@ public function toTrySafe(): TrySafe return TrySafe::failure(new ValueIsNotPresentException()); } - /** @phpstan-return int|string */ - /** @phpstan-return int|string */ + /** @return int|string */ + /** @return int|string */ public function hashCode() { $valueHash = $this->left instanceof IHashable @@ -154,7 +154,7 @@ public function hashCode() return sprintf('%s::left(%s)', self::class, $valueHash); } - /** @phpstan-return Iterator */ + /** @return Iterator */ public function getIterator(): Iterator { return new EmptyIterator(); @@ -197,10 +197,10 @@ public function switch(): Either final public static function right($right): self { return new class ($right) extends Either { - /** @phpstan-var V */ + /** @var V */ private $right; - /** @phpstan-param V $right */ + /** @param V $right */ protected function __construct($right) { $this->right = $right; @@ -258,7 +258,7 @@ public function exists(callable $predicate): bool * * @throws ValueIsNotPresentException * - * @phpstan-return L + * @return L */ public function getLeftUnsafe() { @@ -270,7 +270,7 @@ public function getLeftUnsafe() * * @throws ValueIsNotPresentException * - * @phpstan-return V + * @return V */ public function getRightUnsafe() { @@ -285,9 +285,9 @@ public function resolve(callable $handleLeft, callable $handleRight) /** * @template E * - * @phpstan-param E $else + * @param E $else * - * @phpstan-return V|E + * @return V|E */ public function getOrElse($else) { @@ -299,7 +299,7 @@ public function toTrySafe(): TrySafe return TrySafe::success($this->right); } - /** @phpstan-return int|string */ + /** @return int|string */ public function hashCode() { $valueHash = $this->right instanceof IHashable @@ -308,7 +308,7 @@ public function hashCode() return sprintf('%s::right(%s)', self::class, $valueHash); } - /** @phpstan-return Iterator */ + /** @return Iterator */ public function getIterator(): Iterator { return new ArrayIterator([$this->right]); @@ -346,7 +346,7 @@ public function switch(): Either * * @param callable(R): A $mapper * - * @phpstan-return self + * @return self */ abstract public function map(callable $mapper): self; @@ -355,7 +355,7 @@ abstract public function map(callable $mapper): self; * * @param callable(L): B $mapper * - * @phpstan-return self + * @return self */ abstract public function mapLeft(callable $mapper): self; @@ -364,7 +364,7 @@ abstract public function mapLeft(callable $mapper): self; * * @param V $value * - * @phpstan-return self + * @return self */ final public static function of($value): self { @@ -376,7 +376,7 @@ final public static function of($value): self * * @param V $value * - * @phpstan-return self + * @return self */ final public static function pure($value): self { @@ -388,44 +388,44 @@ abstract public function isRight(): bool; abstract public function isLeft(): bool; /** - * @phpstan-param callable(R): bool $predicate + * @param callable(R): bool $predicate * - * @phpstan-return bool + * @return bool */ abstract public function exists(callable $predicate): bool; /** * @template B * - * @phpstan-param callable(R): self $mapper + * @param callable(R): self $mapper * - * @phpstan-return self + * @return self */ abstract public function flatMap(callable $mapper): self; /** * @template B * - * @phpstan-param callable(L): self $mapper + * @param callable(L): self $mapper * - * @phpstan-return self + * @return self */ abstract public function flatMapLeft(callable $mapper): self; /** * @template A * - * @phpstan-param callable(A, R): A $reducer - * @phpstan-param A $initialReduction + * @param callable(A, R): A $reducer + * @param A $initialReduction * - * @phpstan-return A + * @return A */ final public function reduce(callable $reducer, $initialReduction) { return LazyList::fromIterable($this)->reduce($reducer, $initialReduction); } - /** @phpstan-param callable(R): void $sideEffect */ + /** @param callable(R): void $sideEffect */ abstract public function each(callable $sideEffect): void; /** @@ -436,9 +436,9 @@ abstract public function each(callable $sideEffect): void; * * Complexity: o(1) * - * @phpstan-param callable(R): void $sideEffect + * @param callable(R): void $sideEffect * - * @phpstan-return self + * @return self */ public function tap(callable $sideEffect): self { @@ -457,9 +457,9 @@ public function tap(callable $sideEffect): self * * Complexity: o(1) * - * @phpstan-param callable(L): void $sideEffect + * @param callable(L): void $sideEffect * - * @phpstan-return self + * @return self */ abstract public function tapLeft(callable $sideEffect): self; @@ -468,7 +468,7 @@ abstract public function tapLeft(callable $sideEffect): self; * * @throws ValueIsNotPresentException * - * @phpstan-return L + * @return L */ abstract public function getLeftUnsafe(); @@ -477,26 +477,26 @@ abstract public function getLeftUnsafe(); * * @throws ValueIsNotPresentException * - * @phpstan-return R + * @return R */ abstract public function getRightUnsafe(); /** * @template B * - * @phpstan-param callable(L): B $handleLeft - * @phpstan-param callable(R): B $handleRight + * @param callable(L): B $handleLeft + * @param callable(R): B $handleRight * - * @phpstan-return B + * @return B */ abstract public function resolve(callable $handleLeft, callable $handleRight); /** * @template E * - * @phpstan-param E $else + * @param E $else * - * @phpstan-return R|E + * @return R|E */ abstract public function getOrElse($else); @@ -508,7 +508,7 @@ abstract public function getOrElse($else); * * Right value is preserved and wrapped into `TrySafe::success` * - * @phpstan-return TrySafe + * @return TrySafe */ abstract public function toTrySafe(): TrySafe; @@ -519,21 +519,21 @@ abstract public function toTrySafe(): TrySafe; * * Left value is dropped and replaced with `Option::none` * - * @phpstan-return Option + * @return Option */ abstract public function toOption(): Option; /** * @param self $else * - * @phpstan-return self + * @return self */ abstract public function orElse(self $else): self; /** - * @phpstan-param self $other + * @param self $other * - * @phpstan-return bool + * @return bool */ abstract public function equals($other): bool; diff --git a/src/Bonami/Collection/Enum.php b/src/Bonami/Collection/Enum.php index 2c3e5e0..9154208 100644 --- a/src/Bonami/Collection/Enum.php +++ b/src/Bonami/Collection/Enum.php @@ -14,28 +14,28 @@ abstract class Enum implements IHashable, JsonSerializable { - /** @phpstan-var array> */ + /** @var array> */ private static $instances = []; - /** @phpstan-var array> */ + /** @var array> */ private static $instanceIndex; - /** @phpstan-var null|array, array> */ + /** @var null|array, array> */ private static $constNameIndex; - /** @phpstan-var int|string */ + /** @var int|string */ private $value; - /** @phpstan-param int|string $value */ + /** @param int|string $value */ final private function __construct($value) { $this->value = $value; } /** - * @phpstan-param mixed $value + * @param mixed $value * - * @phpstan-return static + * @return static */ public static function create($value) { @@ -56,13 +56,13 @@ public static function create($value) return self::$instanceIndex[$class][$value]; } - /** @phpstan-return EnumList */ + /** @return EnumList */ public static function instanceList(): EnumList { return EnumList::fromIterable(self::instanceMap()->values()); } - /** @phpstan-return Map */ + /** @return Map */ public static function instanceMap(): Map { $class = static::class; @@ -71,7 +71,7 @@ public static function instanceMap(): Map return self::$instances[$class]; } - /** @phpstan-var iterable $pairs */ + /** @var iterable $pairs */ $pairs = array_map( static function ($value) { return [$value, new static($value)]; @@ -82,16 +82,16 @@ static function ($value) { return self::$instances[$class] = Map::fromIterable($pairs); } - /** @phpstan-return array */ + /** @return array */ private static function getClassConstants(): array { return (new ReflectionClass(static::class))->getConstants(); } /** - * @phpstan-param static ...$enums + * @param static ...$enums * - * @phpstan-return EnumList + * @return EnumList */ public static function getListComplement(self ...$enums) { @@ -99,9 +99,9 @@ public static function getListComplement(self ...$enums) } /** - * @phpstan-param int|string $value + * @param int|string $value * - * @phpstan-return bool + * @return bool */ public static function exists($value): bool { @@ -137,7 +137,7 @@ public function __toString() return (string)$this->getValue(); } - /** @phpstan-return int|string */ + /** @return int|string */ public function getValue() { return $this->value; diff --git a/src/Bonami/Collection/EnumList.php b/src/Bonami/Collection/EnumList.php index f01ccae..b15b2b3 100644 --- a/src/Bonami/Collection/EnumList.php +++ b/src/Bonami/Collection/EnumList.php @@ -7,11 +7,11 @@ /** * @template T of Enum * - * @phpstan-extends ArrayList + * @extends ArrayList */ class EnumList extends ArrayList { - /** @phpstan-return ArrayList */ + /** @return ArrayList */ public function getValueList(): ArrayList { return $this->map(static function (Enum $enum) { @@ -19,7 +19,7 @@ public function getValueList(): ArrayList }); } - /** @phpstan-return array */ + /** @return array */ public function getValues(): array { return $this->getValueList()->toArray(); diff --git a/src/Bonami/Collection/Hash/IHashable.php b/src/Bonami/Collection/Hash/IHashable.php index 0ec1edb..fb385fd 100644 --- a/src/Bonami/Collection/Hash/IHashable.php +++ b/src/Bonami/Collection/Hash/IHashable.php @@ -6,6 +6,6 @@ interface IHashable { - /** @phpstan-return int|string */ + /** @return int|string */ public function hashCode(); } diff --git a/src/Bonami/Collection/LazyList.php b/src/Bonami/Collection/LazyList.php index b4b1475..0feaff5 100644 --- a/src/Bonami/Collection/LazyList.php +++ b/src/Bonami/Collection/LazyList.php @@ -15,28 +15,28 @@ /** * @template T * - * @phpstan-implements IteratorAggregate + * @implements IteratorAggregate */ class LazyList implements IteratorAggregate { /** @use Monad1 */ use Monad1; - /** @phpstan-var iterable */ + /** @var iterable */ private $items; - /** @phpstan-param iterable $iterable */ + /** @param iterable $iterable */ final public function __construct(iterable $iterable) { $this->items = $iterable; } /** - * @phpstan-param int $low - * @phpstan-param int $high - * @phpstan-param int $step + * @param int $low + * @param int $high + * @param int $step * - * @phpstan-return self + * @return self */ public static function range(int $low, int $high = PHP_INT_MAX, int $step = 1): self { @@ -51,10 +51,10 @@ public static function range(int $low, int $high = PHP_INT_MAX, int $step = 1): } /** - * @phpstan-param T $item - * @phpstan-param int|null $size - When no size is passed, infinite items are filled (lazily) + * @param T $item + * @param int|null $size - When no size is passed, infinite items are filled (lazily) * - * @phpstan-return static + * @return static */ public static function fill($item, ?int $size = null) { @@ -71,19 +71,19 @@ public static function fill($item, ?int $size = null) return new static($fill($item, $size)); } - /** @phpstan-return static */ + /** @return static */ public static function fromEmpty() { - /** @phpstan-var array $empty */ + /** @var array $empty */ $empty = []; return new static($empty); } /** - * @phpstan-param array ...$items + * @param array ...$items * - * @phpstan-return static + * @return static */ public static function fromArray(array ...$items) { @@ -93,9 +93,9 @@ public static function fromArray(array ...$items) /** * @template V * - * @phpstan-param iterable $iterable + * @param iterable $iterable * - * @phpstan-return static + * @return static */ public static function fromIterable(iterable $iterable) { @@ -105,9 +105,9 @@ public static function fromIterable(iterable $iterable) /** * @template V * - * @phpstan-param V ...$items + * @param V ...$items * - * @phpstan-return static + * @return static */ public static function of(...$items) { @@ -117,9 +117,9 @@ public static function of(...$items) /** * @template V * - * @phpstan-param V $item + * @param V $item * - * @phpstan-return static + * @return static */ public static function pure($item) { @@ -129,9 +129,9 @@ public static function pure($item) /** * @template B * - * @phpstan-param callable(T, int): B $mapper + * @param callable(T, int): B $mapper * - * @phpstan-return self + * @return self */ public function map(callable $mapper): self { @@ -146,16 +146,16 @@ public function map(callable $mapper): self /** * @template B * - * @phpstan-param callable(T, int): iterable $mapper + * @param callable(T, int): iterable $mapper * - * @phpstan-return self + * @return self */ public function flatMap(callable $mapper): self { return $this->map($mapper)->flatten(); } - /** @phpstan-return self */ + /** @return self */ public function flatten(): self { $flatten = function (): Generator { @@ -170,7 +170,7 @@ public function flatten(): self return new self($flatten()); } - /** @phpstan-param callable(T, int): void $sideEffect */ + /** @param callable(T, int): void $sideEffect */ public function each(callable $sideEffect): void { foreach ($this->items as $key => $item) { @@ -188,9 +188,9 @@ public function each(callable $sideEffect): void * * Complexity: o(n) * - * @phpstan-param callable(T, int): void $sideEffect + * @param callable(T, int): void $sideEffect * - * @phpstan-return static + * @return static */ public function tap(callable $sideEffect) { @@ -209,10 +209,10 @@ public function tap(callable $sideEffect) * * @template R * - * @phpstan-param callable(R, T, int): R $reducer a binary operation for reduction - * @phpstan-param R $initialReduction + * @param callable(R, T, int): R $reducer a binary operation for reduction + * @param R $initialReduction * - * @phpstan-return R + * @return R */ public function reduce(callable $reducer, $initialReduction) { @@ -230,9 +230,9 @@ public function reduce(callable $reducer, $initialReduction) * * @see sum - for trivial summing * - * @phpstan-param Monoid $monoid + * @param Monoid $monoid * - * @phpstan-return T + * @return T */ public function mfold(Monoid $monoid) { @@ -250,9 +250,9 @@ public function mfold(Monoid $monoid) * * @see mfold - for folding diferent types of items (E.g. classes representing BigNumbers and so on) * - * @phpstan-param callable(T): (int|float) $itemToNumber + * @param callable(T): (int|float) $itemToNumber * - * @phpstan-return int|float + * @return int|float */ public function sum(callable $itemToNumber) { @@ -268,10 +268,10 @@ public function sum(callable $itemToNumber) * * @template R * - * @phpstan-param callable(R, T, int): R $scanner a binary operation for scan (reduction) - * @phpstan-param R $initialReduction + * @param callable(R, T, int): R $scanner a binary operation for scan (reduction) + * @param R $initialReduction * - * @phpstan-return self collection with intermediate scan (reduction) results + * @return self collection with intermediate scan (reduction) results */ public function scan(callable $scanner, $initialReduction): self { @@ -287,9 +287,9 @@ public function scan(callable $scanner, $initialReduction): self } /** - * @phpstan-param callable(T, int): bool $predicate + * @param callable(T, int): bool $predicate * - * @phpstan-return static + * @return static */ public function takeWhile(callable $predicate) { @@ -305,9 +305,9 @@ public function takeWhile(callable $predicate) } /** - * @phpstan-param int $size + * @param int $size * - * @phpstan-return static + * @return static */ public function take(int $size) { @@ -324,7 +324,7 @@ public function take(int $size) return new static($take($size)); } - /** @phpstan-return self> */ + /** @return self> */ public function chunk(int $size): self { assert($size > 0, 'Size must be positive'); @@ -346,7 +346,7 @@ public function chunk(int $size): self return new self($chunk($size)); } - /** @phpstan-return Option */ + /** @return Option */ public function head(): Option { return $this->find(static function ($_): bool { @@ -354,7 +354,7 @@ public function head(): Option }); } - /** @phpstan-return Option */ + /** @return Option */ public function last(): Option { // No first item implies there is also no last item, thus we have to return none @@ -366,9 +366,9 @@ public function last(): Option } /** - * @phpstan-param callable(T, int): bool $predicate + * @param callable(T, int): bool $predicate * - * @phpstan-return static + * @return static */ public function filter(callable $predicate) { @@ -383,9 +383,9 @@ public function filter(callable $predicate) } /** - * @phpstan-param callable(T, int): bool $predicate + * @param callable(T, int): bool $predicate * - * @phpstan-return Option + * @return Option */ public function find(callable $predicate): Option { @@ -399,9 +399,9 @@ public function find(callable $predicate): Option } /** - * @phpstan-param callable(T, int): bool $predicate + * @param callable(T, int): bool $predicate * - * @phpstan-return static + * @return static */ public function dropWhile(callable $predicate) { @@ -422,9 +422,9 @@ public function dropWhile(callable $predicate) } /** - * @phpstan-param int $count + * @param int $count * - * @phpstan-return static + * @return static */ public function drop(int $count) { @@ -435,9 +435,9 @@ public function drop(int $count) } /** - * @phpstan-param callable(T, int): bool $predicate + * @param callable(T, int): bool $predicate * - * @phpstan-return bool + * @return bool */ public function exists(callable $predicate): bool { @@ -451,9 +451,9 @@ public function exists(callable $predicate): bool } /** - * @phpstan-param callable(T, int): bool $predicate + * @param callable(T, int): bool $predicate * - * @phpstan-return bool + * @return bool */ public function all(callable $predicate): bool { @@ -469,9 +469,9 @@ public function all(callable $predicate): bool /** * @template B * - * @phpstan-param iterable $iterable + * @param iterable $iterable * - * @phpstan-return self + * @return self */ public function zip(iterable $iterable): self { @@ -507,9 +507,9 @@ public function zip(iterable $iterable): self * * @template B * - * @phpstan-param callable(T, int): B $mapper + * @param callable(T, int): B $mapper * - * @phpstan-return Map + * @return Map */ public function zipMap(callable $mapper): Map { @@ -523,9 +523,9 @@ public function zipMap(callable $mapper): Map /** * @template T2 * - * @phpstan-param iterable ...$iterables + * @param iterable ...$iterables * - * @phpstan-return static + * @return static */ public function concat(iterable ...$iterables) { @@ -539,9 +539,9 @@ public function concat(iterable ...$iterables) } /** - * @phpstan-param T ...$items + * @param T ...$items * - * @phpstan-return static + * @return static */ public function add(...$items) { @@ -549,10 +549,10 @@ public function add(...$items) } /** - * @phpstan-param int $position - * @phpstan-param iterable $iterable + * @param int $position + * @param iterable $iterable * - * @phpstan-return static + * @return static */ public function insertOnPosition(int $position, iterable $iterable) { @@ -576,7 +576,7 @@ public function insertOnPosition(int $position, iterable $iterable) return new static($insertOnPosition($position, $iterable)); } - /** @phpstan-return array */ + /** @return array */ public function toArray(): array { return iterator_to_array($this->getIterator(), false); @@ -587,13 +587,13 @@ public function join(string $glue): string return implode($glue, $this->toArray()); } - /** @phpstan-return Iterator */ + /** @return Iterator */ public function getIterator(): Iterator { return $this->createIterator($this->items); } - /** @phpstan-return ArrayList */ + /** @return ArrayList */ public function toList(): ArrayList { return ArrayList::fromIterable($this); @@ -607,19 +607,19 @@ public function toList(): ArrayList * * Complexity: o(n) * - * @phpstan-return Map + * @return Map */ public function toMap(): Map { - /** @phpstan-var array */ + /** @var array */ $pairs = $this->toArray(); return Map::fromIterable($pairs); } /** - * @phpstan-param iterable $iterable + * @param iterable $iterable * - * @phpstan-return Iterator + * @return Iterator */ private function createIterator(iterable $iterable): Iterator { diff --git a/src/Bonami/Collection/Map.php b/src/Bonami/Collection/Map.php index 934cac4..0524dfd 100644 --- a/src/Bonami/Collection/Map.php +++ b/src/Bonami/Collection/Map.php @@ -30,17 +30,17 @@ * @template K * @template V * - * @phpstan-implements IteratorAggregate + * @implements IteratorAggregate */ class Map implements Countable, IteratorAggregate { - /** @phpstan-var array */ + /** @var array */ protected $keys; - /** @phpstan-var array */ + /** @var array */ protected $values; - /** @phpstan-param array $items */ + /** @param array $items */ final public function __construct(array $items) { $this->keys = []; @@ -63,9 +63,9 @@ final public function __construct(array $items) * * @see fromIterable if you need to create Map from array of pairs (2-dimensional array) * - * @phpstan-param array $array + * @param array $array * - * @phpstan-return static + * @return static */ public static function fromAssociativeArray(array $array) { @@ -77,10 +77,10 @@ public static function fromAssociativeArray(array $array) * * Complexity: o(1) * - * @phpstan-param K $key - * @phpstan-param V $value + * @param K $key + * @param V $value * - * @phpstan-return static + * @return static */ public static function fromOnly($key, $value) { @@ -95,9 +95,9 @@ public static function fromOnly($key, $value) * * @see getOrElse for getting default value in case the key does not exists * - * @phpstan-param K $key + * @param K $key * - * @phpstan-return Option + * @return Option */ public function get($key): Option { @@ -117,11 +117,11 @@ public function get($key): Option * * @throws OutOfBoundsException * - * @phpstan-return V + * @return V * * @see getOrElse for getting default value in case the key does not exists * - * @phpstan-param K $key + * @param K $key * * @see get for getting value the safe way */ @@ -160,7 +160,7 @@ public function getUnsafe($key) * * Complexity: o(n) * - * @phpstan-return ArrayList + * @return ArrayList */ public function values(): ArrayList { @@ -176,10 +176,10 @@ public function values(): ArrayList * * @template E * - * @phpstan-param K $key - * @phpstan-param E $defaultValue + * @param K $key + * @param E $defaultValue * - * @phpstan-return V|E + * @return V|E */ public function getOrElse($key, $defaultValue) { @@ -205,7 +205,7 @@ public function getOrElse($key, $defaultValue) * Complexity: o(1) - getting the iterator itself is o(1) because it uses yield internally. * Iterating over the iterator is of course o(n) * - * @phpstan-return Iterator + * @return Iterator */ public function getIterator(): Iterator { @@ -221,7 +221,7 @@ public function getIterator(): Iterator * * @see isNotEmpty * - * @phpstan-return bool + * @return bool */ public function isEmpty(): bool { @@ -233,7 +233,7 @@ public function isEmpty(): bool * * Complexity: o(1) * - * @phpstan-return int + * @return int */ public function count(): int { @@ -247,7 +247,7 @@ public function count(): int * * @see isEmpty * - * @phpstan-return bool + * @return bool */ public function isNotEmpty(): bool { @@ -262,10 +262,10 @@ public function isNotEmpty(): bool * * @see exists if you need to check value existance more losely other then strict comparison * - * @phpstan-param V $value - * @phpstan-param bool|null $strictComparison + * @param V $value + * @param bool|null $strictComparison * - * @phpstan-return bool + * @return bool */ public function contains($value, ?bool $strictComparison = true): bool { @@ -277,9 +277,9 @@ public function contains($value, ?bool $strictComparison = true): bool * * Complexity: o(1) * - * @phpstan-param K $key + * @param K $key * - * @phpstan-return bool + * @return bool */ public function has($key): bool { @@ -297,9 +297,9 @@ public function has($key): bool * * @template B * - * @phpstan-param callable(K, V): B $mapper + * @param callable(K, V): B $mapper * - * @phpstan-return self + * @return self */ public function mapKeys(callable $mapper): self { @@ -327,7 +327,7 @@ public function mapKeys(callable $mapper): self * * Complexity: o(1) * - * @phpstan-return static + * @return static */ public static function fromEmpty() { @@ -345,9 +345,9 @@ public static function fromEmpty() * @see map - for mapping both keys and values and returning ArrayList as result * @see mapKeys - for mapping just keys and keeping Map as result * - * @phpstan-param callable(V, K): B $mapper + * @param callable(V, K): B $mapper * - * @phpstan-return self + * @return self */ public function mapValues(callable $mapper): self { @@ -375,11 +375,11 @@ public function mapValues(callable $mapper): self * * Complexity: o(n) * - * @phpstan-return array + * @return array */ public function toAssociativeArray(): array { - /** @phpstan-var array */ + /** @var array */ $assoc = array_combine( array_map(static function ($key) { return (string)$key; @@ -402,9 +402,9 @@ public function toAssociativeArray(): array * @template K2 * @template V2 * - * @phpstan-param Map $mergeMap + * @param Map $mergeMap * - * @phpstan-return static + * @return static */ public function concat(Map $mergeMap) { @@ -436,9 +436,9 @@ public function concat(Map $mergeMap) * @see filterKeys - for filtering original map with predicate in keys only * @see withoutKeys - for simply removing values by given keys no matter what the value is * - * @phpstan-param Map $map + * @param Map $map * - * @phpstan-return static + * @return static */ public function minus(Map $map) { @@ -455,9 +455,9 @@ public function minus(Map $map) * * @see filterKeys - if your predicate needs just keys * - * @phpstan-param callable(V, K): bool $predicate + * @param callable(V, K): bool $predicate * - * @phpstan-return static + * @return static */ public function filter(callable $predicate) { @@ -478,9 +478,9 @@ public function filter(callable $predicate) * * Complexity: o(n) * - * @phpstan-param callable(V, K): void $sideEffect + * @param callable(V, K): void $sideEffect * - * @phpstan-return void + * @return void */ public function each(callable $sideEffect): void { @@ -496,9 +496,9 @@ public function each(callable $sideEffect): void * * Complexity: o(n) * - * @phpstan-param callable(V, K): void $sideEffect + * @param callable(V, K): void $sideEffect * - * @phpstan-return static + * @return static */ public function tap(callable $sideEffect) { @@ -516,9 +516,9 @@ public function tap(callable $sideEffect) * * @see filter - if your predicate needs values too * - * @phpstan-param callable(K): bool $predicate + * @param callable(K): bool $predicate * - * @phpstan-return static + * @return static */ public function filterKeys(callable $predicate) { @@ -538,9 +538,9 @@ public function filterKeys(callable $predicate) * * @see exists - if you just need to check if some pair matches given predicate * - * @phpstan-param callable(V, K): bool $predicate + * @param callable(V, K): bool $predicate * - * @phpstan-return Option + * @return Option */ public function find(callable $predicate): Option { @@ -557,9 +557,9 @@ public function find(callable $predicate): Option * * Complexity: o(n) - stops when predicate matches * - * @phpstan-param callable(K, V): bool $predicate + * @param callable(K, V): bool $predicate * - * @phpstan-return Option + * @return Option */ public function findKey(callable $predicate): Option { @@ -576,11 +576,11 @@ public function findKey(callable $predicate): Option * * Complexity: o(n) - where n is `$size` * - * @phpstan-return static + * @return static */ public function take(int $size) { - /** @phpstan-var array */ + /** @var array */ $zipped = array_map( null, array_slice($this->keys, 0, $size, true), @@ -596,9 +596,9 @@ public function take(int $size) * * Complexity: o(n) - there are different hidden constants cost varying on given iterable. * - * @phpstan-param Map|iterable $iterable + * @param Map|iterable $iterable * - * @phpstan-return static + * @return static */ public static function fromIterable(iterable $iterable) { @@ -628,11 +628,11 @@ public static function fromIterable(iterable $iterable) * * Complexity: o(n) * - * @phpstan-return array + * @return array */ public function getItems(): array { - /** @phpstan-var array */ + /** @var array */ $zipped = array_map(null, $this->keys, $this->values); return $zipped; @@ -645,9 +645,9 @@ public function getItems(): array * * @see find - if you just need to find concreate value-key pair that satisfies given predicate * - * @phpstan-param callable(V, K): bool $predicate + * @param callable(V, K): bool $predicate * - * @phpstan-return bool + * @return bool */ public function exists(callable $predicate): bool { @@ -664,9 +664,9 @@ public function exists(callable $predicate): bool * * Complexity: o(n) - stops immediately when predicate does not match * - * @phpstan-param callable(V, K): bool $predicate + * @param callable(V, K): bool $predicate * - * @phpstan-return bool + * @return bool */ public function all(callable $predicate): bool { @@ -683,7 +683,7 @@ public function all(callable $predicate): bool * * Complexity: o(n) * - * @phpstan-return static + * @return static */ public function withoutNulls() { @@ -698,9 +698,9 @@ public function withoutNulls() * * Complexity: o(n) * - * @phpstan-param iterable $keys + * @param iterable $keys * - * @phpstan-return static + * @return static */ public function withoutKeys(iterable $keys) { @@ -733,9 +733,9 @@ public function withoutKeys(iterable $keys) * * Complexity: o(n) * - * @phpstan-param K $key + * @param K $key * - * @phpstan-return static + * @return static */ public function withoutKey($key) { @@ -761,11 +761,11 @@ public function withoutKey($key) * * Complexity: o(n*log(n)) * - * @phpstan-param callable(K, K):int|null $comparator - A standard comparator expecting two arguments + * @param callable(K, K):int|null $comparator - A standard comparator expecting two arguments * returning values -1, 0 or 1. When no comparator is passed, * standard <=> operator is used to between values. * - * @phpstan-return static + * @return static */ public function sortKeys(?callable $comparator = null) { @@ -780,9 +780,9 @@ public function sortKeys(?callable $comparator = null) * * Complexity: o(n) * - * @phpstan-param iterable $keys + * @param iterable $keys * - * @phpstan-return static + * @return static */ public function getByKeys(iterable $keys) { @@ -816,7 +816,7 @@ public function getByKeys(iterable $keys) * * Complexity: o(n) * - * @phpstan-return ArrayList + * @return ArrayList */ public function keys(): ArrayList { @@ -831,11 +831,11 @@ public function keys(): ArrayList * * Complexity: o(n*log(n)) * - * @phpstan-param callable(V, V):int|null $comparator - A standard comparator expecting two arguments + * @param callable(V, V):int|null $comparator - A standard comparator expecting two arguments * returning values -1, 0 or 1. When no comparator is passed, * standard <=> operator is used to between values. * - * @phpstan-return static + * @return static */ public function sortValues(?callable $comparator = null) { @@ -852,7 +852,7 @@ public function sortValues(?callable $comparator = null) * * Complexity: o(n) * - * @phpstan-return ArrayList + * @return ArrayList */ public function pairs(): ArrayList { @@ -866,13 +866,13 @@ public function pairs(): ArrayList * * @template R * - * @phpstan-param callable(R, V, K): R $reducer - takes up to 3 parametrs and returns next reduction step: + * @param callable(R, V, K): R $reducer - takes up to 3 parametrs and returns next reduction step: * (?prevReduction, ?currentValue, ?currentKey) => nextReduction * - * @phpstan-param R $initialReduction - an initial reduction used for the first reduction step as prevReduction. + * @param R $initialReduction - an initial reduction used for the first reduction step as prevReduction. * It is also immediately returned if the collection is empty. * - * @phpstan-return R + * @return R */ public function reduce(callable $reducer, $initialReduction) { @@ -891,9 +891,9 @@ public function reduce(callable $reducer, $initialReduction) * * Complexity: o(n) * - * @phpstan-param int $size - A size of resulting Map chunk + * @param int $size - A size of resulting Map chunk * - * @phpstan-return ArrayList> - a list of Map chunks of size $size + * @return ArrayList> - a list of Map chunks of size $size */ public function chunk(int $size): ArrayList { @@ -935,13 +935,13 @@ public function __toString(): string * * @template B * - * @phpstan-param callable(V, K): B $mapper + * @param callable(V, K): B $mapper * - * @phpstan-return ArrayList + * @return ArrayList */ public function map(callable $mapper): ArrayList { - /** @phpstan-var array $mapped */ + /** @var array $mapped */ $mapped = array_map($mapper, $this->values, $this->keys); return ArrayList::fromIterable($mapped); diff --git a/src/Bonami/Collection/Monad1.php b/src/Bonami/Collection/Monad1.php index 22875b3..d76567f 100644 --- a/src/Bonami/Collection/Monad1.php +++ b/src/Bonami/Collection/Monad1.php @@ -36,9 +36,9 @@ final public static function ap(self $closure, self $argument): self * * @template B * - * @phpstan-param callable(T, int): iterable $mapper + * @param callable(T, int): iterable $mapper * - * @phpstan-return self + * @return self */ abstract public function flatMap(callable $mapper): self; } diff --git a/src/Bonami/Collection/Monad2.php b/src/Bonami/Collection/Monad2.php index d9a05c3..2eb74f7 100644 --- a/src/Bonami/Collection/Monad2.php +++ b/src/Bonami/Collection/Monad2.php @@ -39,9 +39,9 @@ final public static function ap(self $closure, self $argument): self * * @template B * - * @phpstan-param callable(R, int): iterable $mapper + * @param callable(R, int): iterable $mapper * - * @phpstan-return self + * @return self */ abstract public function flatMap(callable $mapper): self; } diff --git a/src/Bonami/Collection/Monoid/DoubleProductMonoid.php b/src/Bonami/Collection/Monoid/DoubleProductMonoid.php index 06d821a..dfc6ade 100644 --- a/src/Bonami/Collection/Monoid/DoubleProductMonoid.php +++ b/src/Bonami/Collection/Monoid/DoubleProductMonoid.php @@ -4,7 +4,7 @@ namespace Bonami\Collection\Monoid; -/** @phpstan-implements Monoid */ +/** @implements Monoid */ class DoubleProductMonoid implements Monoid { public function concat($a, $b) diff --git a/src/Bonami/Collection/Monoid/DoubleSumMonoid.php b/src/Bonami/Collection/Monoid/DoubleSumMonoid.php index 0d73227..9a489e5 100644 --- a/src/Bonami/Collection/Monoid/DoubleSumMonoid.php +++ b/src/Bonami/Collection/Monoid/DoubleSumMonoid.php @@ -4,7 +4,7 @@ namespace Bonami\Collection\Monoid; -/** @phpstan-implements Monoid */ +/** @implements Monoid */ class DoubleSumMonoid implements Monoid { public function concat($a, $b) diff --git a/src/Bonami/Collection/Monoid/IntProductMonoid.php b/src/Bonami/Collection/Monoid/IntProductMonoid.php index acea850..d00957c 100644 --- a/src/Bonami/Collection/Monoid/IntProductMonoid.php +++ b/src/Bonami/Collection/Monoid/IntProductMonoid.php @@ -4,7 +4,7 @@ namespace Bonami\Collection\Monoid; -/** @phpstan-implements Monoid */ +/** @implements Monoid */ class IntProductMonoid implements Monoid { public function concat($a, $b): int diff --git a/src/Bonami/Collection/Monoid/IntSumMonoid.php b/src/Bonami/Collection/Monoid/IntSumMonoid.php index b3eb9db..b6a36dd 100644 --- a/src/Bonami/Collection/Monoid/IntSumMonoid.php +++ b/src/Bonami/Collection/Monoid/IntSumMonoid.php @@ -4,7 +4,7 @@ namespace Bonami\Collection\Monoid; -/** @phpstan-implements Monoid */ +/** @implements Monoid */ class IntSumMonoid implements Monoid { public function concat($a, $b): int diff --git a/src/Bonami/Collection/Monoid/Monoid.php b/src/Bonami/Collection/Monoid/Monoid.php index 9d76582..6b592b9 100644 --- a/src/Bonami/Collection/Monoid/Monoid.php +++ b/src/Bonami/Collection/Monoid/Monoid.php @@ -14,17 +14,17 @@ interface Monoid * - associativity - `concat(concat($a, $b), $c) === concat($a, concat($b, $c))` for any element `A` * - identity law - `concat($a, getEmpty()) === concat(getEmpty(), $a) === $a` * - * @phpstan-param A $a - * @phpstan-param A $b + * @param A $a + * @param A $b * - * @phpstan-return A + * @return A */ public function concat($a, $b); /** * Neutral element for binary concat operation * - * @phpstan-return A + * @return A */ public function getEmpty(); } diff --git a/src/Bonami/Collection/Monoid/OptionMonoid.php b/src/Bonami/Collection/Monoid/OptionMonoid.php index 6452c1f..8ffc5f5 100644 --- a/src/Bonami/Collection/Monoid/OptionMonoid.php +++ b/src/Bonami/Collection/Monoid/OptionMonoid.php @@ -9,24 +9,24 @@ /** * @template T * - * @phpstan-implements Monoid> + * @implements Monoid> */ class OptionMonoid implements Monoid { - /** @phpstan-var Monoid */ + /** @var Monoid */ private $monoid; - /** @phpstan-param Monoid $monoid */ + /** @param Monoid $monoid */ public function __construct(Monoid $monoid) { $this->monoid = $monoid; } /** - * @phpstan-param Option $a - * @phpstan-param Option $b + * @param Option $a + * @param Option $b * - * @phpstan-return Option + * @return Option */ public function concat($a, $b): Option { @@ -35,7 +35,7 @@ public function concat($a, $b): Option })($a, $b); } - /** @phpstan-return Option */ + /** @return Option */ public function getEmpty(): Option { return Option::some($this->monoid->getEmpty()); diff --git a/src/Bonami/Collection/Monoid/StringMonoid.php b/src/Bonami/Collection/Monoid/StringMonoid.php index 41bd210..43ab335 100644 --- a/src/Bonami/Collection/Monoid/StringMonoid.php +++ b/src/Bonami/Collection/Monoid/StringMonoid.php @@ -4,7 +4,7 @@ namespace Bonami\Collection\Monoid; -/** @phpstan-implements Monoid */ +/** @implements Monoid */ class StringMonoid implements Monoid { public function concat($a, $b): string diff --git a/src/Bonami/Collection/Mutable/Map.php b/src/Bonami/Collection/Mutable/Map.php index 3c1fdee..a88bae4 100644 --- a/src/Bonami/Collection/Mutable/Map.php +++ b/src/Bonami/Collection/Mutable/Map.php @@ -10,13 +10,13 @@ * @template K * @template V * - * @phpstan-extends \Bonami\Collection\Map + * @extends \Bonami\Collection\Map */ class Map extends \Bonami\Collection\Map { /** - * @phpstan-param K $key - * @phpstan-param V $value + * @param K $key + * @param V $value */ public function add($key, $value): void { @@ -26,10 +26,10 @@ public function add($key, $value): void } /** - * @phpstan-param K $key - * @phpstan-param V $value + * @param K $key + * @param V $value * - * @phpstan-return V + * @return V */ public function getOrAdd($key, $value) { diff --git a/src/Bonami/Collection/Option.php b/src/Bonami/Collection/Option.php index 6d7e3d5..db07d05 100644 --- a/src/Bonami/Collection/Option.php +++ b/src/Bonami/Collection/Option.php @@ -14,29 +14,29 @@ /** * @template T * - * @phpstan-implements IteratorAggregate + * @implements IteratorAggregate */ abstract class Option implements IHashable, IteratorAggregate { /** @use Monad1 */ use Monad1; - /** @phpstan-var self|null */ + /** @var self|null */ private static $none; /** * @template V * - * @phpstan-param ?V $value + * @param ?V $value * - * @phpstan-return self + * @return self */ final public static function fromNullable($value): self { return $value === null ? self::none() : self::some($value); } - /** @phpstan-return self */ + /** @return self */ final public static function none(): Option { return self::$none ?? self::$none = new class extends Option { @@ -85,7 +85,7 @@ public function exists(callable $predicate): bool * * @throws ValueIsNotPresentException * - * @phpstan-return T + * @return T */ public function getUnsafe() { @@ -95,9 +95,9 @@ public function getUnsafe() /** * @template E * - * @phpstan-param E $else + * @param E $else * - * @phpstan-return T|E + * @return T|E */ public function getOrElse($else) { @@ -121,13 +121,13 @@ public function toEither($left): Either return Either::left($left); } - /** @phpstan-return int|string */ + /** @return int|string */ public function hashCode() { return spl_object_hash($this); // There should be only one instance of none } - /** @phpstan-return Iterator */ + /** @return Iterator */ public function getIterator(): Iterator { return new EmptyIterator(); @@ -153,17 +153,17 @@ public function __toString(): string /** * @template V * - * @phpstan-param V $value + * @param V $value * - * @phpstan-return self + * @return self */ final public static function some($value): self { return new class ($value) extends Option { - /** @phpstan-var V */ + /** @var V */ private $value; - /** @phpstan-param V $value */ + /** @param V $value */ protected function __construct($value) { $this->value = $value; @@ -216,7 +216,7 @@ public function exists(callable $predicate): bool * * @throws ValueIsNotPresentException * - * @phpstan-return V + * @return V */ public function getUnsafe() { @@ -226,9 +226,9 @@ public function getUnsafe() /** * @template E * - * @phpstan-param E $else + * @param E $else * - * @phpstan-return V|E + * @return V|E */ public function getOrElse($else) { @@ -252,7 +252,7 @@ public function toEither($left): Either return Either::right($this->value); } - /** @phpstan-return int|string */ + /** @return int|string */ public function hashCode() { $valueHash = $this->value instanceof IHashable @@ -261,7 +261,7 @@ public function hashCode() return sprintf('%s::some(%s)', self::class, $valueHash); } - /** @phpstan-return Iterator */ + /** @return Iterator */ public function getIterator(): Iterator { return new ArrayIterator([$this->value]); @@ -287,18 +287,18 @@ public function __toString(): string /** * @template B * - * @phpstan-param callable(T): B $mapper + * @param callable(T): B $mapper * - * @phpstan-return self + * @return self */ abstract public function map(callable $mapper): self; /** * @template V * - * @phpstan-param V $value + * @param V $value * - * @phpstan-return self + * @return self */ final public static function of($value) { @@ -308,9 +308,9 @@ final public static function of($value) /** * @template V * - * @phpstan-param V $value + * @param V $value * - * @phpstan-return self + * @return self */ final public static function pure($value) { @@ -322,42 +322,42 @@ abstract public function isDefined(): bool; abstract public function isEmpty(): bool; /** - * @phpstan-param callable(T): bool $predicate + * @param callable(T): bool $predicate * - * @phpstan-return self + * @return self */ abstract public function filter(callable $predicate): self; /** - * @phpstan-param callable(T): bool $predicate + * @param callable(T): bool $predicate * - * @phpstan-return bool + * @return bool */ abstract public function exists(callable $predicate): bool; /** * @template B * - * @phpstan-param callable(T): self $mapper + * @param callable(T): self $mapper * - * @phpstan-return self + * @return self */ abstract public function flatMap(callable $mapper): self; /** * @template R * - * @phpstan-param callable(R, T): R $reducer - * @phpstan-param R $initialReduction + * @param callable(R, T): R $reducer + * @param R $initialReduction * - * @phpstan-return R + * @return R */ final public function reduce(callable $reducer, $initialReduction) { return LazyList::fromIterable($this)->reduce($reducer, $initialReduction); } - /** @phpstan-param callable(T): void $sideEffect */ + /** @param callable(T): void $sideEffect */ abstract public function each(callable $sideEffect): void; /** @@ -368,9 +368,9 @@ abstract public function each(callable $sideEffect): void; * * Complexity: o(1) * - * @phpstan-param callable(T): void $sideEffect + * @param callable(T): void $sideEffect * - * @phpstan-return self + * @return self */ public function tap(callable $sideEffect): self { @@ -389,9 +389,9 @@ public function tap(callable $sideEffect): self * * Complexity: o(1) * - * @phpstan-param callable(): void $sideEffect + * @param callable(): void $sideEffect * - * @phpstan-return self + * @return self */ abstract public function tapNone(callable $sideEffect): self; @@ -400,20 +400,20 @@ abstract public function tapNone(callable $sideEffect): self; * * @throws ValueIsNotPresentException * - * @phpstan-return T + * @return T */ abstract public function getUnsafe(); /** * @template E * - * @phpstan-param E $else + * @param E $else * - * @phpstan-return T|E + * @return T|E */ abstract public function getOrElse($else); - /** @phpstan-return TrySafe */ + /** @return TrySafe */ abstract public function toTrySafe(): TrySafe; /** @@ -421,7 +421,7 @@ abstract public function toTrySafe(): TrySafe; * * @param L $left * - * @phpstan-return Either + * @return Either */ abstract public function toEither($left): Either; @@ -438,26 +438,26 @@ public function toArray(): array } /** - * @phpstan-param self $else + * @param self $else * - * @phpstan-return self + * @return self */ abstract public function orElse(self $else): self; /** * @template B * - * @phpstan-param callable(): B $handleNone - * @phpstan-param callable(T): B $handleSome + * @param callable(): B $handleNone + * @param callable(T): B $handleSome * - * @phpstan-return B + * @return B */ abstract public function resolve(callable $handleNone, callable $handleSome); /** - * @phpstan-param self $value + * @param self $value * - * @phpstan-return bool + * @return bool */ final public function equals($value): bool { diff --git a/src/Bonami/Collection/TrySafe.php b/src/Bonami/Collection/TrySafe.php index 370924f..34424fd 100644 --- a/src/Bonami/Collection/TrySafe.php +++ b/src/Bonami/Collection/TrySafe.php @@ -15,7 +15,7 @@ /** * @template T * - * @phpstan-implements IteratorAggregate + * @implements IteratorAggregate */ abstract class TrySafe implements IHashable, IteratorAggregate { @@ -25,9 +25,9 @@ abstract class TrySafe implements IHashable, IteratorAggregate /** * @template V * - * @phpstan-param V $value + * @param V $value * - * @phpstan-return self + * @return self */ final public static function of($value): self { @@ -37,9 +37,9 @@ final public static function of($value): self /** * @template V * - * @phpstan-param V $value + * @param V $value * - * @phpstan-return self + * @return self */ final public static function pure($value): self { @@ -49,9 +49,9 @@ final public static function pure($value): self /** * @template V * - * @phpstan-param callable(): V $callable + * @param callable(): V $callable * - * @phpstan-return self + * @return self */ final public static function fromCallable(callable $callable): self { @@ -65,18 +65,18 @@ final public static function fromCallable(callable $callable): self /** * @template V * - * @phpstan-param V $value + * @param V $value * - * @phpstan-return self + * @return self */ final public static function success($value): self { - /** @phpstan-extends TrySafe */ + /** @extends TrySafe */ return new class ($value) extends TrySafe { - /** @phpstan-var V */ + /** @var V */ private $value; - /** @phpstan-param V $value */ + /** @param V $value */ protected function __construct($value) { $this->value = $value; @@ -137,7 +137,7 @@ public function recoverWithIf(callable $predicate, callable $recovery): TrySafe return $this; } - /** @phpstan-return V */ + /** @return V */ public function getUnsafe() { return $this->value; @@ -146,9 +146,9 @@ public function getUnsafe() /** * @template E * - * @phpstan-param E $else + * @param E $else * - * @phpstan-return V|E + * @return V|E */ public function getOrElse($else) { @@ -176,13 +176,13 @@ public function resolve(callable $handleFailure, callable $handleSuccess) return $handleSuccess($this->value); } - /** @phpstan-return Iterator */ + /** @return Iterator */ public function getIterator(): Iterator { return new ArrayIterator([$this->value]); } - /** @phpstan-return int|string */ + /** @return int|string */ public function hashCode() { $valueHash = $this->value instanceof IHashable @@ -194,15 +194,15 @@ public function hashCode() } /** - * @phpstan-param Throwable $failure + * @param Throwable $failure * - * @phpstan-return self + * @return self */ final public static function failure(Throwable $failure): TrySafe { - /** @phpstan-extends TrySafe */ + /** @extends TrySafe */ return new class ($failure) extends TrySafe { - /** @phpstan-var Throwable */ + /** @var Throwable */ private $failure; protected function __construct(Throwable $failure) @@ -280,7 +280,7 @@ public function recoverWithIf(callable $predicate, callable $recovery): TrySafe * * @throws ValueIsNotPresentException * - * @phpstan-return T + * @return T */ public function getUnsafe() { @@ -290,9 +290,9 @@ public function getUnsafe() /** * @template E * - * @phpstan-param E $else + * @param E $else * - * @phpstan-return T|E + * @return T|E */ public function getOrElse($else) { @@ -319,13 +319,13 @@ public function resolve(callable $handleFailure, callable $handleSuccess) return $handleFailure($this->failure); } - /** @phpstan-return Iterator */ + /** @return Iterator */ public function getIterator(): Iterator { return new EmptyIterator(); } - /** @phpstan-return int|string */ + /** @return int|string */ public function hashCode() { $failureHash = $this->failure instanceof IHashable @@ -339,18 +339,18 @@ public function hashCode() /** * @template B * - * @phpstan-param callable(T): B $mapper + * @param callable(T): B $mapper * - * @phpstan-return self + * @return self */ abstract public function map(callable $mapper): self; /** * @template B * - * @phpstan-param callable(T): self $mapper + * @param callable(T): self $mapper * - * @phpstan-return self + * @return self */ abstract public function flatMap(callable $mapper): self; @@ -359,9 +359,9 @@ abstract public function flatMap(callable $mapper): self; * * Complexity: o(1) * - * @phpstan-param callable(T): void $sideEffect + * @param callable(T): void $sideEffect * - * @phpstan-return void + * @return void */ public function each(callable $sideEffect): void { @@ -378,9 +378,9 @@ public function each(callable $sideEffect): void * * Complexity: o(1) * - * @phpstan-param callable(T): void $sideEffect + * @param callable(T): void $sideEffect * - * @phpstan-return self + * @return self */ public function tap(callable $sideEffect): self { @@ -399,19 +399,19 @@ public function tap(callable $sideEffect): self * * Complexity: o(1) * - * @phpstan-param callable(Throwable): void $sideEffect + * @param callable(Throwable): void $sideEffect * - * @phpstan-return self + * @return self */ abstract public function tapFailure(callable $sideEffect): self; /** * @template R * - * @phpstan-param callable(R, T): R $reducer - * @phpstan-param R $initialReduction + * @param callable(R, T): R $reducer + * @param R $initialReduction * - * @phpstan-return R + * @return R */ final public function reduce(callable $reducer, $initialReduction) { @@ -419,9 +419,9 @@ final public function reduce(callable $reducer, $initialReduction) } /** - * @phpstan-param self $value + * @param self $value * - * @phpstan-return bool + * @return bool */ final public function equals($value): bool { @@ -430,9 +430,9 @@ final public function equals($value): bool } /** - * @phpstan-param callable(Throwable): T $callable + * @param callable(Throwable): T $callable * - * @phpstan-return self + * @return self */ abstract public function recover(callable $callable): self; @@ -442,17 +442,17 @@ abstract public function recover(callable $callable): self; * Recovery must return directly the value or throw another exception * (which is automatically wrapped into TrySafe) * - * @phpstan-param callable(Throwable): bool $predicate - * @phpstan-param callable(Throwable): T $recovery + * @param callable(Throwable): bool $predicate + * @param callable(Throwable): T $recovery * - * @phpstan-return self + * @return self */ abstract public function recoverIf(callable $predicate, callable $recovery): self; /** - * @phpstan-param callable(Throwable): TrySafe $callable + * @param callable(Throwable): TrySafe $callable * - * @phpstan-return self + * @return self */ abstract public function recoverWith(callable $callable): self; @@ -462,10 +462,10 @@ abstract public function recoverWith(callable $callable): self; * Recovery must return TrySafe::success() if the recovery is successful or TrySafe::failure() if it fails. * That allows chaining multiple calls with possible failure. * - * @phpstan-param callable(Throwable): bool $predicate - checks if conditions are met to run recovery. - * @phpstan-param callable(Throwable): TrySafe $recovery - a recovery you want to try run + * @param callable(Throwable): bool $predicate - checks if conditions are met to run recovery. + * @param callable(Throwable): TrySafe $recovery - a recovery you want to try run * - * @phpstan-return self + * @return self */ abstract public function recoverWithIf(callable $predicate, callable $recovery): self; @@ -481,23 +481,23 @@ final public function isFailure(): bool * * @throws ValueIsNotPresentException * - * @phpstan-return T + * @return T */ abstract public function getUnsafe(); /** * @template E * - * @phpstan-param E $else + * @param E $else * - * @phpstan-return T|E + * @return T|E */ abstract public function getOrElse($else); /** @throws ValueIsNotPresentException */ abstract public function getFailureUnsafe(): Throwable; - /** @phpstan-return Option */ + /** @return Option */ abstract public function toOption(): Option; /** @return Either */ @@ -506,10 +506,10 @@ abstract public function toEither(): Either; /** * @template B * - * @phpstan-param callable(Throwable): B $handleFailure - * @phpstan-param callable(T): B $handleSuccess + * @param callable(Throwable): B $handleFailure + * @param callable(T): B $handleSuccess * - * @phpstan-return B + * @return B */ abstract public function resolve(callable $handleFailure, callable $handleSuccess); } diff --git a/src/Bonami/Collection/helpers.php b/src/Bonami/Collection/helpers.php index 4be25b8..92b168e 100644 --- a/src/Bonami/Collection/helpers.php +++ b/src/Bonami/Collection/helpers.php @@ -46,9 +46,9 @@ function falsy(): callable * * @template A * - * @phpstan-param A $arg $args + * @param A $arg $args * - * @phpstan-return callable(callable(A): mixed): mixed + * @return callable(callable(A): mixed): mixed */ function applicator1($arg): callable { @@ -75,9 +75,9 @@ function compose(callable $f, callable $g): callable } /** - * @phpstan-param mixed $key + * @param mixed $key * - * @phpstan-return int|string + * @return int|string */ function hashKey($key) { From b97f466098149f21fa0f910eb5c6b5ed5da07955 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 14 Jan 2022 12:11:11 +0100 Subject: [PATCH 12/28] Update doc for function currying --- README.md | 32 +---------------------- src/Bonami/Collection/CurriedFunction.php | 15 ++++++++--- 2 files changed, 12 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index c30faf6..72f9450 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ $top10 = frequencyAnalysis($text) - `\Bonami\Collection\EnumList` - List of Enums, extending ArrayList - [`\Bonami\Collection\Option`](#option) - Immutable structure for representing, that you maybe have value and maybe not. It provides safe (functional) approach to handle null pointer errors. - [`\Bonami\Collection\TrySafe`](#trysafe) - Immutable structure for representing, that you have value or error generated upon the way. It provides safe (functional) approach to handle errors without side effects. -- `\Bonami\Collection\Lambda` - Wrapper around callable providing currying. Currying is very useful for some functional patterns +- [`\Bonami\Collection\CurriedFunction`](./docs/curried-function.md) - Represents single argument function. It can create curried version of multi argument function, which is better for some function programming composition patterns. ### Type classes @@ -145,36 +145,6 @@ We are using [phpstan](https://phpstan.org/) annotations for better type safety, resolving, we created optional dependency [phpstan-collections](https://github.com/bonami/phpstan-collections), which we strongly suggest installing if you use phpstan. It fixes some type resolving, especially for late static binding. -### Currying - -If higher order functions are said to be bread & butter of functional programming then currying is ... well ... the spice of it. The concept is simple - it is transforming function taking multiple arguments into sequence of functions each taking single argument. - -Since PHP does not provide us with any means of currying, we implemented own callable wrapper `Lambda` capable of the task: - -```php -$greeter = fn (string $greeting, string $name): string => "{$greeting} {$name}!"; - -$helloGreeter = Lambda::of($greeter)("Hello"); -echo $helloGreeter("John"); // Hello John! -echo $helloGreeter("Paul"); // Hello Paul! - -$holaGreeter = Lambda::of($greeter)("Hola"); -echo $holaGreeter("Diego"); // Hola Diego! -``` - -To be more developer friendly, it is possible to call functions either with multiple arguments or with single argument per call or even combine the both: - -```php -$sumThree = Lambda::of(fn (int $x, int $y, int $z): int => $x + $y + $z); - -$sumThree(7)(42)(666); -$sumThree(7)(42, 666); -$sumThree(7, 42)(666); -$sumThree(7, 42, 666); -``` - -All invocations will yield the same result. - ### Option > aka how to avoid billion dollar mistake by using `Option` (we are looking in your direction, `null`!) diff --git a/src/Bonami/Collection/CurriedFunction.php b/src/Bonami/Collection/CurriedFunction.php index 6402454..ab09e60 100644 --- a/src/Bonami/Collection/CurriedFunction.php +++ b/src/Bonami/Collection/CurriedFunction.php @@ -9,6 +9,8 @@ use ReflectionFunction; /** + * Represents single argument function + * * @template I * @template O */ @@ -45,6 +47,9 @@ private function __construct(callable $callable, int $expectedNumberOfArgs, arra } /** + * Wraps single argument callable into CurriedFunction. It is semantically the same, but it allows calling methods + * on it, like `map` for function composition. + * * @template A * @template Z * @@ -1068,16 +1073,18 @@ public static function curry30(callable $callable): self /** * Mapping over function is equivalent of composing functions * + * `$f->map($g)` is equivalent of `g ∘ f` or `g(f(x))` in mathematics notation. + * * @template A * - * @param CurriedFunction $callable + * @param CurriedFunction $then * * @return CurriedFunction */ - public function map(CurriedFunction $callable): CurriedFunction + public function map(CurriedFunction $then): CurriedFunction { - return self::of(function ($arg) use ($callable) { - return $callable($this($arg)); + return self::of(function ($arg) use ($then) { + return $then($this($arg)); }); } From 5545f4dd356bd9e49bf43b46eb1f9e31d4c18e54 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 14 Jan 2022 12:11:22 +0100 Subject: [PATCH 13/28] fixup! [BC] Rework applicatives, monads, function currying --- tests/Bonami/Collection/CurriedFunctionTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Bonami/Collection/CurriedFunctionTest.php b/tests/Bonami/Collection/CurriedFunctionTest.php index d833474..544ce3c 100644 --- a/tests/Bonami/Collection/CurriedFunctionTest.php +++ b/tests/Bonami/Collection/CurriedFunctionTest.php @@ -4,7 +4,6 @@ namespace Bonami\Collection; -use Bonami\Collection\Exception\InvalidStateException; use PHPUnit\Framework\TestCase; class CurriedFunctionTest extends TestCase From b2b572660c3f0e6e67da928828e133d487e83f2f Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 21 Jan 2022 11:51:41 +0100 Subject: [PATCH 14/28] fixup! Update doc for function currying --- docs/curried-function.md | 82 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 docs/curried-function.md diff --git a/docs/curried-function.md b/docs/curried-function.md new file mode 100644 index 0000000..e72b98a --- /dev/null +++ b/docs/curried-function.md @@ -0,0 +1,82 @@ +# CurriedFunction + +Represents single argument function. Provides static factories to create curried versions of multi argument functions. + +## Currying + +The concept is simple - it is transforming function taking multiple arguments into sequence of functions each taking single argument. + +```php +$greeter = fn (string $greeting, string $name): string => "{$greeting} {$name}!"; + +$curriedGreeter = CurriedFunction::curry2($greeter); + +$englishGreeter = $curriedGreeter("Hello"); // partial apply +echo $englishGreeter("John"); // Hello John! +echo $englishGreeter("Paul"); // Hello Paul! + +$spanishGreeter = $curriedGreeter("Hola"); // partial apply +echo $spanishGreeter("Diego"); // Hola Diego! +``` + +You might wonder, where this can be useful. We can leverage this everywhere, where we expect single argument closure but we have two arguments function. + +E.g. + +```php +$strings = ArrayList::of('a', 'b'); +$times1 = ArrayList::of(1, 2, 3); +$times2 = ArrayList::of(4); + +$strRepeat = CurriedFunction::self::curry2(str_repeat(...)); + +$partiallyApplied = $strings->map($strRepeat); + +// ArrayList::fromIterable(['a', 'aa', 'aaa', 'b', 'bb', 'bbb'] +$fullyApplied1 = $partiallyApplied->flatMap(fn ($pa) => $times1->map($pa)); + +// ArrayList::fromIterable(['aaaa', 'bbbb'] +$fullyApplied2 = $partiallyApplied->flatMap(fn ($pa) => $times2->map($pa)); +``` + +API provides factories to curry functions with up to 30 arguments. Reason to have factories by number of arguments is to provide type safety. +If you use phpstan (which we strongly recommend), it can check all input parameters. + +## Composition + +Single argument functions are easy to compose. We provide `map` function for this purpose. + +```php +$plusOne = fn (int $i): int => $i + 1; +$timesTwo = fn (int $i): int => $i * 2; + +$plusOneThenTimesTwo = CurriedFunction::of($plusOne)->map($timesTwo); +$plusOneThenTimesTwo(5); // 12 +``` + +`$f->map($g)` is equivalent of `g ∘ f` or `g(f(x))` in mathematics notation. + +```php +$composed1 = $f->map($g); +$composed2 = fn ($x) => $g($f($x)); +// $composed1 and $composed2 are equivalent +``` + +With phpstan, it also checks input / output arguments and creates typed version of composed function. +```php +function foo(string $s): int { + return strlen($s); +} + +/** +* @param int $i +* @return array + */ +function bar(int $i): array { + return array_fill(0, $i, 'a'); +} +// accepts string and returns array. +// composed type is CurriedFunction> which is equivalent of callable(string): array +$foobar = CurriedFunction::of(foo(...))->map(CurriedFunction::of(bar(...))); +$foobar('abc'); // ['a', 'a', 'a'] +``` From b1450371f9408605c60063359a6e34a845eae4b4 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 21 Jan 2022 11:51:59 +0100 Subject: [PATCH 15/28] Update doc for type-classes --- README.md | 10 +--------- docs/type-classes.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 docs/type-classes.md diff --git a/README.md b/README.md index 72f9450..50974b6 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ - [Show me the code!](#motivation) - [Features](#features) - [Structures](#structures) - - [Type classes](#type-classes) - [Type safety](#type-safety) - [Currying](#currying) - [Option](#option) - [TrySafe](#trysafe) - [Lift operator](#lift-operator) - [Traverse](#traverse) +- [Type classes](./docs/type-classes.md) - [License](#features) - [Contributing](#features) @@ -131,14 +131,6 @@ $top10 = frequencyAnalysis($text) - [`\Bonami\Collection\TrySafe`](#trysafe) - Immutable structure for representing, that you have value or error generated upon the way. It provides safe (functional) approach to handle errors without side effects. - [`\Bonami\Collection\CurriedFunction`](./docs/curried-function.md) - Represents single argument function. It can create curried version of multi argument function, which is better for some function programming composition patterns. -### Type classes - -- `\Bonami\Collection\ArrayList`, `\Bonami\Collection\LazyList`, `\Bonami\Collection\Option`, `\Bonami\Collection\TrySafe` are Monads, which means that they support - - `->map` with functor laws - - `::of` (pure) and `->ap` (apply) with applicative laws - - `->flatMap` (bind) with monadic laws - - on top of that they support many friendly functional methods (like `exists`, `all`, `find` etc.) - ### Type safety We are using [phpstan](https://phpstan.org/) annotations for better type safety, utilizing generics. For even better type diff --git a/docs/type-classes.md b/docs/type-classes.md new file mode 100644 index 0000000..8811fe4 --- /dev/null +++ b/docs/type-classes.md @@ -0,0 +1,44 @@ +# Type classes + +Type class is bigger set of classes, that has some common behavior we wont to abstract. +Php has very basic type system and even with phpstan it is hard to do encode it somehow meaningfully. + +Ideally we would have higher kinder generics, which we haven't. So we chose traits, because we can +exploit the way how they are mixed in. We can use `self` and `static` keyword in those traits and they +are bounded to the class they are mixed into. + +Also we can mixin multiple type-class trairs into class, which is something we actually want to do. + +Type-class traits we define: +- `\Bonami\Collection\Applicative1` applicative with 1 hole for generic type +- `\Bonami\Collection\Applicative2` applicative with 2 holes for generic types +- `\Bonami\Collection\Monad1` monad with 1 hole for generic type, uses `\Bonami\Collection\Applicative1` +- `\Bonami\Collection\Monad2` monad with 2 holes for generic types, uses `\Bonami\Collection\Monad2` + +## Applicative + +Applicative defines abstract methods: +- `pure` - wraps single value into `Applicative` instance. Or more theoretically: pulls impure value into `Applicative` instance context. +- `ap` - applies single value to callback in context of `Applicative` +- `map` - maps over values in context of `Applicative` + +Class that mixin this trait needs to implement them. It should implement them in a way, that they obey applicative laws. + +If the class do, it also gain these methods for free: +- `lift1` - `lift30` - factory for augmenting callable to accept and return values wrapped in `Applicative` context. Supports up to 30 fixed arguments. +- `lift` - generic version of lift above. The generic version has worse type safety checks. +- `sequence` - operation to combine multiple `Applicative` instances into single `Applicative` instances containg multiple values (in `ArrayList`). +- `travese` - similar to `sequence` allowing transformation of the values along the way. + +## Monad + +`Monad` uses `Applicative` trait and defines one extra abstract method: +- `flatMap` - chains operation on `Monad` + +Class that mixin this trait needs to implement all methods from `Monad` and `Applicative` as well except `Applicative::ap` method, +that is already implemented in `Monad`. + +## Overriding methods + +Sometimes concrete type-class instance (the class that uses type-class trait) can have more optimal version of +"derived" method. Mixing trait into does not forbid overriding it with more optimal version. From cd470211522ab6ff65666b1dc62a1a8fd0484f48 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 21 Jan 2022 11:52:22 +0100 Subject: [PATCH 16/28] Use shorter php 8.1 syntax in docs --- README.md | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 50974b6..8398713 100644 --- a/README.md +++ b/README.md @@ -37,29 +37,18 @@ use Bonami\Collection\ArrayList; class Person { - private string $name; - private int $age; - - public function __construct(string $name, int $age) { - $this->name = $name; - $this->age = $age; - } - - public function getName(): string { - return $this->name; - } - - public function getAge(): int { - return $this->age; - } + public function __construct( + private readonly string $name, + private readonly int $age + ) {} } $persons = ArrayList::of(new Person('John', 31), new Person('Jacob', 22), new Person('Arthur', 29)); $names = $persons - ->filter(fn (Person $person): bool => $person->getAge() <= 30) - ->sort(fn (Person $a, Person $b): int => $a->getName() <=> $b->getName()) - ->map(fn (Person $person): string => $person->getName()) + ->filter(fn (Person $person): bool => $person->age <= 30) + ->sort(fn (Person $a, Person $b): int => $a->name <=> $b->name) + ->map(fn (Person $person): string => $person->name) ->join(";"); // $names = "Arthur;Jacob" From 330175f6f12118c782930486983d04d2360b7b08 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 21 Jan 2022 11:52:43 +0100 Subject: [PATCH 17/28] fixup! Update doc for type-classes --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8398713..4620f6a 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ $coloredObjects = ArrayList::fromIterable($colors) use Bonami\Collection\ArrayList; $concat = fn (string $first, string $second) => "{$first} {$second}"; -$coloredObjects = ArrayList::lift($concat)($colors, $objects); +$coloredObjects = ArrayList::lift2($concat)($colors, $objects); ``` ### Character frequency analysis From ecd43eb1caaf7d074b8f3dc3716c527a52a13ae2 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 21 Jan 2022 12:47:48 +0100 Subject: [PATCH 18/28] Add previous exception to failure This can be handy for debugging --- src/Bonami/Collection/TrySafe.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bonami/Collection/TrySafe.php b/src/Bonami/Collection/TrySafe.php index 34424fd..cafe39b 100644 --- a/src/Bonami/Collection/TrySafe.php +++ b/src/Bonami/Collection/TrySafe.php @@ -284,7 +284,7 @@ public function recoverWithIf(callable $predicate, callable $recovery): TrySafe */ public function getUnsafe() { - throw new ValueIsNotPresentException('Can not get value from Failure'); + throw new ValueIsNotPresentException('Can not get value from Failure', 0, $this->failure); } /** From 07e4a2b049d2cc9bca49a5bbfd651fa12aa80d3a Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 21 Jan 2022 13:08:10 +0100 Subject: [PATCH 19/28] Implement Iterable1 typeclass This way we can easily prototype Iterable structures and ensure same interface on multiple stuctures without actual interface. Concreate class using the trait should override methods for optimization when needed. --- src/Bonami/Collection/Iterable1.php | 270 ++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 src/Bonami/Collection/Iterable1.php diff --git a/src/Bonami/Collection/Iterable1.php b/src/Bonami/Collection/Iterable1.php new file mode 100644 index 0000000..65b65c1 --- /dev/null +++ b/src/Bonami/Collection/Iterable1.php @@ -0,0 +1,270 @@ + mixed + * @param R $initialReduction - initial value used as seed for $carry + * + * @return R - reduced values. If the list is empty, $initialReduction is directly returned + */ + abstract public function reduce(callable $reducer, $initialReduction); + + /** @return Iterator */ + abstract public function getIterator(): Iterator; + + /** + * Reduce (folds) to single value using Monoid + * + * Complexity: o(n) + * + * @see sum - for trivial summing + * + * @param Monoid $monoid + * + * @return T + */ + public function mfold(Monoid $monoid) + { + return $this->reduce(static function ($carry, $next) use ($monoid) { + return $monoid->concat($carry, $next); + }, $monoid->getEmpty()); + } + + /** + * Converts items to numbers and then sums them up. + * + * Complexity: o(n) + * + * @see mfold - for folding diferent types of items (E.g. classes representing BigNumbers and so on) + * + * @param callable(T): (int|float) $itemToNumber + * + * @return int|float + */ + public function sum(callable $itemToNumber) + { + return $this->reduce(static function ($carry, $next) use ($itemToNumber) { + return $carry + $itemToNumber($next); + }, 0); + } + + /** + * Finds first item by given predicate where it matches + * + * Complexity: o(n) + * + * @see exists - if you just need to check if something matches by predicate + * @see findKey - if you need to get key by predicate + * + * @param callable(T, int): bool $predicate + * + * @return Option + */ + public function find(callable $predicate): Option + { + foreach ($this->getIterator() as $key => $item) { + if ($predicate($item, $key)) { + return Option::some($item); + } + } + return Option::none(); + } + + /** + * Gets the very first value + * + * Complexity: o(1) + * + * @return Option item wrapped with Option::some or Option::none if empty + */ + public function head(): Option + { + return $this->find(static fn () => true); + } + + /** + * Gets the very last value + * + * Complexity: o(n) + * + * @return Option item wrapped with Option::some or Option::none if empty + */ + public function last(): Option + { + return $this->reduce(static fn ($curry, $next) => Option::of($next), $this->head()); + } + + /** + * Finds minimal value defined by comparator + * + * Complexity: o(n) + * + * @param null|callable(T, T): int $comparator - classic comparator returning 1, 0 or -1 + * if no comparator is passed, $first <=> $second is used + * + * @return Option minimal value wrapped in Option::some or Option::none when list is empty + */ + public function min(?callable $comparator = null): Option + { + $comparator ??= comparator(); + $min = Option::lift2(static fn ($a, $b) => $comparator($a, $b) <= 0 ? $a : $b); + return $this->reduce( + static fn ($next, $carry) => $min($next, Option::of($carry)), + $this->head() + ); + } + + /** + * Finds maximal value defined by comparator + * + * Complexity: o(n) + * + * @param null|callable(T, T): int $comparator - classic comparator returning 1, 0 or -1 + * if no comparator is passed, $first <=> $second is used + * + * @return Option minimal value wrapped in Option::some or Option::none when list is empty + */ + public function max(?callable $comparator = null): Option + { + $comparator ??= comparator(); + $max = Option::lift2(static fn ($a, $b) => $comparator($a, $b) > 0 ? $a : $b); + return $this->reduce( + static fn ($next, $carry) => $max($next, Option::of($carry)), + $this->head() + ); + } + + /** + * Checks if AT LEAST ONE item satisfies predicate. + * + * Complexity: o(n) + * + * @see find - if you need to get item by predicate + * @see all - if you need to check if ALL items in List satisfy predicate + * + * @param callable(T, int): bool $predicate + * + * @return bool + */ + public function exists(callable $predicate): bool + { + return $this->find($predicate)->isDefined(); + } + + /** + * Checks if ALL items satisfy predicate + * + * Complexity: o(n) + * + * @see exists - if you need to check if AT LEAST ONE item in List satisfy predicate + * @see find - if you need to get item by predicate + * + * @param callable(T, int): bool $predicate + * + * @return bool + */ + public function all(callable $predicate): bool + { + return !$this->exists(static fn ($item, int $i) => !$predicate($item, $i)); + } + + /** + * Executes $sideEffect on each item of List + * + * Complexity: o(n) + * + * @param callable(T, int): void $sideEffect + * + * @return void + */ + public function each(callable $sideEffect): void + { + foreach ($this->getIterator() as $key => $item) { + $sideEffect($item, $key); + } + } + + /** + * Executes $sideEffect on each item and returns unchanged instance. + * + * Allows inserting side-effects in a chain of method calls + * + * Complexity: o(n) + * + * @param callable(T, int): void $sideEffect + * + * @return static + */ + public function tap(callable $sideEffect) + { + foreach ($this->getIterator() as $key => $item) { + $sideEffect($item, $key); + } + + return $this; + } + + /** + * Gets classic php native array for interoperability + * + * Complexity: o(1) + * + * @return array + */ + public function toArray(): array + { + return iterator_to_array($this->getIterator(), false); + } + + /** + * Gets classic php native array for interoperability + * + * Complexity: o(1) + * + * @return ArrayList + */ + public function toList(): ArrayList + { + return ArrayList::fromIterable($this->getIterator()); + } + + public function count(): int + { + return count($this->toArray()); + } + + /** + * @see isNotEmpty + * + * @return bool + */ + public function isEmpty(): bool + { + return $this->count() === 0; + } + + /** + * @see isEmpty + * + * @return bool + */ + public function isNotEmpty(): bool + { + return $this->count() !== 0; + } +} From 18645a0f7d444c665e46451cbb134629e668b4c0 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 21 Jan 2022 15:25:39 +0100 Subject: [PATCH 20/28] Use Iterable1 in our structs --- src/Bonami/Collection/ArrayList.php | 2 ++ src/Bonami/Collection/LazyList.php | 2 ++ src/Bonami/Collection/Option.php | 4 +++- src/Bonami/Collection/TrySafe.php | 2 ++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Bonami/Collection/ArrayList.php b/src/Bonami/Collection/ArrayList.php index a4585a7..fe916e2 100644 --- a/src/Bonami/Collection/ArrayList.php +++ b/src/Bonami/Collection/ArrayList.php @@ -45,6 +45,8 @@ class ArrayList implements Countable, IteratorAggregate, JsonSerializable { /** @use Monad1 */ use Monad1; + /** @use Iterable1 */ + use Iterable1; /** @var array */ protected $items; diff --git a/src/Bonami/Collection/LazyList.php b/src/Bonami/Collection/LazyList.php index 0feaff5..87451d2 100644 --- a/src/Bonami/Collection/LazyList.php +++ b/src/Bonami/Collection/LazyList.php @@ -21,6 +21,8 @@ class LazyList implements IteratorAggregate { /** @use Monad1 */ use Monad1; + /** @use Iterable1 */ + use Iterable1; /** @var iterable */ private $items; diff --git a/src/Bonami/Collection/Option.php b/src/Bonami/Collection/Option.php index db07d05..0afab71 100644 --- a/src/Bonami/Collection/Option.php +++ b/src/Bonami/Collection/Option.php @@ -20,6 +20,8 @@ abstract class Option implements IHashable, IteratorAggregate { /** @use Monad1 */ use Monad1; + /** @use Iterable1 */ + use Iterable1; /** @var self|null */ private static $none; @@ -329,7 +331,7 @@ abstract public function isEmpty(): bool; abstract public function filter(callable $predicate): self; /** - * @param callable(T): bool $predicate + * @param callable(T, int=): bool $predicate * * @return bool */ diff --git a/src/Bonami/Collection/TrySafe.php b/src/Bonami/Collection/TrySafe.php index cafe39b..e839dfa 100644 --- a/src/Bonami/Collection/TrySafe.php +++ b/src/Bonami/Collection/TrySafe.php @@ -21,6 +21,8 @@ abstract class TrySafe implements IHashable, IteratorAggregate { /** @use Monad1 */ use Monad1; + /** @use Iterable1 */ + use Iterable1; /** * @template V From 1d725c5453d3d795718681815287e17bde5026f6 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 21 Jan 2022 15:38:41 +0100 Subject: [PATCH 21/28] Document Iterable1 --- docs/type-classes.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/type-classes.md b/docs/type-classes.md index 8811fe4..9179129 100644 --- a/docs/type-classes.md +++ b/docs/type-classes.md @@ -14,6 +14,7 @@ Type-class traits we define: - `\Bonami\Collection\Applicative2` applicative with 2 holes for generic types - `\Bonami\Collection\Monad1` monad with 1 hole for generic type, uses `\Bonami\Collection\Applicative1` - `\Bonami\Collection\Monad2` monad with 2 holes for generic types, uses `\Bonami\Collection\Monad2` +- `\Bonami\Collection\Iterable1` iterable / foldable struct 1 hole for generic type ## Applicative @@ -38,7 +39,38 @@ If the class do, it also gain these methods for free: Class that mixin this trait needs to implement all methods from `Monad` and `Applicative` as well except `Applicative::ap` method, that is already implemented in `Monad`. +## Iterable + +Iterable defines only 2 abstract methods: +- `reduce` - for reducing structure to single value +- `getIterator` - a method compatible with `\IteratorAggregate` iterface + +From those 2 simple methods we can derive lots of useful methods for free: +- `mfold` - left folding via `\Bonami\Collection\Monoid\Monoid` instance +- `sum` - transforms item to integer / float and then sums them together +- `find` - finds item by predicate +- `head` - gets very first item if present +- `last` - gets very last item if present +- `min` - gets minimal item by comparator +- `max`- gets maximal item by comparator +- `exists` - checks if at least one element matches the predicate +- `all` - checks if all elements matches the predicate +- `each` - executes side effect on each element +- `tap` - executes side effect on each element and return self +- `toArray` - converts structure to `array` +- `toList` - converts structure to `\Bonami\Collection\ArrayList` +- `count` - counts number of elements +- `isEmpty` - checks if the structure is empty +- `isNotEmpty` - checks if the structure is not empty + ## Overriding methods Sometimes concrete type-class instance (the class that uses type-class trait) can have more optimal version of "derived" method. Mixing trait into does not forbid overriding it with more optimal version. + +## Caveats of traits + +They do surprisingly good job for us, but they have one big drawback: they are not types themselves. + +This mean we cannot use them anywhere in code in typehints and we cannot check object instances if +they are `instanceof` some concrete trait. From 5baabddd157b0bdf9f4baaf3c694c5697e6fc5e2 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 21 Jan 2022 15:45:33 +0100 Subject: [PATCH 22/28] fixup! Use shorter php 8.1 syntax in docs --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 4620f6a..0e0969f 100644 --- a/README.md +++ b/README.md @@ -189,7 +189,6 @@ function printUserAgeById(int $id): void { } } - ``` ```php @@ -213,7 +212,7 @@ function getAgeByUserEmail(string $email): ?int { // The better way using `Option` function printUserAgeById(int $id): void { print Option::fromNullable(getUserEmailById($id)) - ->flatMap(fn (string $email) => Option::fromNullable(getAgeByUserEmail($email))) + ->flatMap(Option::fromNullable(getAgeByUserEmail(...)) ->map(fn (int $age): string => "Age of user with id {$id} is {$age}") ->getOrElse("Dont know age of user with id {$id}"); From f0a7b3799d24cd7efedb6eb0d066ab2155722d94 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 21 Jan 2022 16:58:34 +0100 Subject: [PATCH 23/28] Separate and update Option doc into own file --- README.md | 100 +------------------------------------ docs/option.md | 131 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 99 deletions(-) create mode 100644 docs/option.md diff --git a/README.md b/README.md index 0e0969f..2becdf1 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ $top10 = frequencyAnalysis($text) - `\Bonami\Collection\LazyList` - Wrapper on any iterable structure. It leverages yield internally making it lazy. It can save memory significantly. - [`\Bonami\Collection\Enum`](./docs/enum.md) - Not a collection, but has great synergy with rest of the library. Meant for defining closed enumerations. Provides interesting methods like getting complements list of values for given enum. - `\Bonami\Collection\EnumList` - List of Enums, extending ArrayList -- [`\Bonami\Collection\Option`](#option) - Immutable structure for representing, that you maybe have value and maybe not. It provides safe (functional) approach to handle null pointer errors. +- [`\Bonami\Collection\Option`](./docs/option.md) - Immutable structure for representing, that you maybe have value and maybe not. It provides safe (functional) approach to handle null pointer errors. - [`\Bonami\Collection\TrySafe`](#trysafe) - Immutable structure for representing, that you have value or error generated upon the way. It provides safe (functional) approach to handle errors without side effects. - [`\Bonami\Collection\CurriedFunction`](./docs/curried-function.md) - Represents single argument function. It can create curried version of multi argument function, which is better for some function programming composition patterns. @@ -126,104 +126,6 @@ We are using [phpstan](https://phpstan.org/) annotations for better type safety, resolving, we created optional dependency [phpstan-collections](https://github.com/bonami/phpstan-collections), which we strongly suggest installing if you use phpstan. It fixes some type resolving, especially for late static binding. -### Option - -> aka how to avoid billion dollar mistake by using `Option` (we are looking in your direction, `null`!) - -`Option` type encapsulates value, which may or may not exist. If you are not familiar with concept of `Option` (also called `Maybe` in some languages), think of `ArrayList` which is either empty or has single item inside. - -Value which exists is represented by instance of `Some` class, whereas missing one is `None`. - -```php -use Bonami\Collection\Option; - -$somethingToEat = Option::some("ice cream"); -$nothingToSeeHere = Option::none(); -``` - -The good thing is that we can operate on `Some` & `None` the same way: - -```php -use Bonami\Collection\Option; - -$somethingToEat = Option::some("ice cream"); -$nothingToSeeHere = Option::none(); - -$iLikeToEat = fn (string $food): string => "I like to eat tasty {$food}!"; - -$somethingToEat->map($iLikeToEat); // Will map to string "I like to eat tasty ice cream!" wrapped in `Some` instance -$nothingToSeeHere->map($iLikeToEat); // `None`, wont be mapped and will stay the same - -``` - -We can use `Option` as better and more safe alternative to nullable values since handling of `null` may easily become cumbersome. Compare following code examples: - -```php -function getUserEmailById(int $id): ?string { - $usersDb = [ - 1 => "john@foobar.baz", - 2 => "paul@foobar.baz", - ]; - return $usersDb[$id] ?? null; -} -function getAgeByUserEmail(string $email): ?int { - $ageDb = [ - "john@foobar.baz" => 66, - "diego@hola.esp" => 42, - ]; - return $ageDb[$email] ?? null; -} - -// The old good `null` way -function printUserAgeById(int $id): void { - $email = getUserEmailById($id); - $age = null; - if ($email !== null) { - $age = getAgeByUserEmail($email); - - } - if ($age === null) { - print "Dont know age of user with id {$id}"; - } else { - print "Age of user with id {$id} is {$age}"; - } - -} -``` - -```php -use Bonami\Collection\Option; - -function getUserEmailById(int $id): ?string { - $usersDb = [ - 1 => "john@foobar.baz", - 2 => "paul@foobar.baz", - ]; - return $usersDb[$id] ?? null; -} -function getAgeByUserEmail(string $email): ?int { - $ageDb = [ - "john@foobar.baz" => 66, - "diego@hola.esp" => 42, - ]; - return $ageDb[$email] ?? null; -} - -// The better way using `Option` -function printUserAgeById(int $id): void { - print Option::fromNullable(getUserEmailById($id)) - ->flatMap(Option::fromNullable(getAgeByUserEmail(...)) - ->map(fn (int $age): string => "Age of user with id {$id} is {$age}") - ->getOrElse("Dont know age of user with id {$id}"); - -} -``` - -You can see that the second example using `Option` allows us to sequence computations so that if any of intermediate steps yields `None`, the subsequent computations are simply ignored. -We hope you have a grasp of it, even though example is rather artificial ;-) - -In case you are a functional programming zealot, you'd like to hear that `Option` is a lawful monad (thus functor & applicative). - ### TrySafe Make long story short: what `Option` is for possible missing (nullable) values, `TrySafe` is for possible exceptions. diff --git a/docs/option.md b/docs/option.md new file mode 100644 index 0000000..43d11fd --- /dev/null +++ b/docs/option.md @@ -0,0 +1,131 @@ +# Option + +> aka how to avoid billion dollar mistake by using `Option` (we are looking in your direction, `null`!) + +`Option` type encapsulates value, which may or may not exist. If you are not familiar with concept of `Option` (also called `Maybe` in some languages), think of `ArrayList` which is either empty or has single item inside. + +Value which exists is represented in `some` instance, whereas missing one is `none`. + +```php +use Bonami\Collection\Option; + +$somethingToEat = Option::some("ice cream"); +$nothingToSeeHere = Option::none(); +``` + +The good thing is that we can operate on `some` & `none` the same way: + +```php +use Bonami\Collection\Option; + +$somethingToEat = Option::some("ice cream"); +$nothingToSeeHere = Option::none(); + +$iLikeToEat = fn (string $food): string => "I like to eat tasty {$food}!"; + +$somethingToEat->map($iLikeToEat); // Will map to string "I like to eat tasty ice cream!" wrapped in `some` instance +$nothingToSeeHere->map($iLikeToEat); // `none`, wont be mapped and will stay the same +``` + +We can use `Option` as better and more safe alternative to nullable values since handling of `null` may easily become cumbersome. + +## Example + +Imagine we have some (dummy) functions like this: + +```php +function getUserEmailById(int $id): ?string { + $usersDb = [ + 1 => "john@foobar.baz", + 2 => "paul@foobar.baz", + ]; + return $usersDb[$id] ?? null; +} +function getAgeByUserEmail(string $email): ?int { + $ageDb = [ + "john@foobar.baz" => 66, + "diego@hola.esp" => 42, + ]; + return $ageDb[$email] ?? null; +} +``` + +Classical way to combine these `with` null will look something like this: + +```php +function printUserAgeById(int $id): void { + $email = getUserEmailById($id); + $age = null; + if ($email !== null) { + $age = getAgeByUserEmail($email); + + } + if ($age === null) { + print "Dont know age of user with id {$id}"; + } else { + print "Age of user with id {$id} is {$age}"; + } +} +``` + +With `Option` we can do better: + +```php +function printUserAgeById(int $id): void { + print Option::fromNullable(getUserEmailById($id)) + ->flatMap(Option::fromNullable(getAgeByUserEmail(...)) + ->map(fn (int $age): string => "Age of user with id {$id} is {$age}") + ->getOrElse("Dont know age of user with id {$id}"); +} +``` + +Or we can design our methods to work with `Option` in a first place: +```php +/** + * @param int $id + * @return Option + */ +function getUserEmailById(int $id): Option { + $usersDb = [ + 1 => "john@foobar.baz", + 2 => "paul@foobar.baz", + ]; + return Option::fromNullable($usersDb[$id] ?? null); +} +/** + * @param string $email + * @return Option + */ +function getAgeByUserEmail(string $email): Option { + $ageDb = [ + "john@foobar.baz" => 66, + "diego@hola.esp" => 42, + ]; + return Option::fromNullable($ageDb[$email] ?? null); +} +``` + +And then: + +```php +function printUserAgeById(int $id): void { + print getUserEmailById($id) + ->flatMap(getAgeByUserEmail(...)) + ->map(fn (int $age): string => "Age of user with id {$id} is {$age}") + ->getOrElse("Dont know age of user with id {$id}"); +} +``` + +You can see that the example using `Option` allows us to sequence (chain) computations so that if +any of intermediate steps yields `none`, the subsequent computations are simply ignored. +We hope you have a grasp of it, even though example is rather artificial ;-) + +## Type classes + +Option mixes `Applicative1`, `Monad1` and `Iterable1` traits. +If you don't know, what [type-class](./type-classes.md) is, don't despair. It simply means, +that it has some common behaviour with other structures and that it has quite rich interface +of methods that it gets (from those traits). + +In case you are a functional programming zealot, you'd like to hear that `Option` +is a lawful monad (thus functor & applicative). From 91beed6df9068ac0d81b582c71024fdcd6ee5cf2 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 21 Jan 2022 17:27:21 +0100 Subject: [PATCH 24/28] Separate and update TrySafe doc --- README.md | 126 +---------------------------------------------- docs/try-safe.md | 112 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 125 deletions(-) create mode 100644 docs/try-safe.md diff --git a/README.md b/README.md index 2becdf1..d3fcdcf 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ $top10 = frequencyAnalysis($text) - [`\Bonami\Collection\Enum`](./docs/enum.md) - Not a collection, but has great synergy with rest of the library. Meant for defining closed enumerations. Provides interesting methods like getting complements list of values for given enum. - `\Bonami\Collection\EnumList` - List of Enums, extending ArrayList - [`\Bonami\Collection\Option`](./docs/option.md) - Immutable structure for representing, that you maybe have value and maybe not. It provides safe (functional) approach to handle null pointer errors. -- [`\Bonami\Collection\TrySafe`](#trysafe) - Immutable structure for representing, that you have value or error generated upon the way. It provides safe (functional) approach to handle errors without side effects. +- [`\Bonami\Collection\TrySafe`](./docs/try-safe.md) - Immutable structure for representing, that you have value or error generated upon the way. It provides safe (functional) approach to handle errors without side effects. - [`\Bonami\Collection\CurriedFunction`](./docs/curried-function.md) - Represents single argument function. It can create curried version of multi argument function, which is better for some function programming composition patterns. ### Type safety @@ -126,130 +126,6 @@ We are using [phpstan](https://phpstan.org/) annotations for better type safety, resolving, we created optional dependency [phpstan-collections](https://github.com/bonami/phpstan-collections), which we strongly suggest installing if you use phpstan. It fixes some type resolving, especially for late static binding. -### TrySafe - -Make long story short: what `Option` is for possible missing (nullable) values, `TrySafe` is for possible exceptions. - -Throwing exceptions and catching them somewhere may seem as a good way how to handle error states throughout your code. Except that it is not... - -Consider following code - can you guess the outcome of calling possible implementation of `compute` method from signature? -```php -interface Div { - public function compute(int $a, int $b): float; -} -``` -Most of the time, the method will be well-behaved and will return `float` according to return type declaration. Until we pass `0` as second argument: - -```php -class DivImplementation { - public function compute(int $a, int $b): float { - if ($b === 0) { - throw new RuntimeException("Can not divide by zero, bro"); - } - return $a / $b; - } -} -``` -The problem is that `compute` is not defined for every possible combination of arguments (it is [partial function](https://en.wikipedia.org/wiki/Partial_function)) and the signature is kind of lying to us. We must look at the specific function implementation body to see if there is possibility for exception to be thrown. - -We can do better with the little help of `TrySafe` class: - -```php -use Bonami\Collection\TrySafe; - -interface Div { - public function compute(int $a, int $b): TrySafe; -} - -class DivImplementation { - public function compute(int $a, int $b): TrySafe { - return $b === 0 - ? TrySafe::failure(new RuntimeException("Can not divide by zero, bro")) - : TrySafe::success($a / $b); - } -} - -$div = new DivImplementation(); -$outcome = $div->compute(10, 0); - -``` - -Now we have the outcome of `compute` call safely wrapped in `TrySafe` instances and can do the further computations with it no matter if it is `Success` or `Failure`. - -You can use `TrySafe` to wrap unsafe (throwing) calls and chain the computations the same way as with `Option`: - -```php -use Bonami\Collection\TrySafe; - -$getTheUltimateAnswerOrThrow = function(bool $shouldThrow): int { - if ($shouldThrow) { - throw new RuntimeException("There is no ultimate answer!"); - } - return 42; -}; - -$makeTheAnswerBiggerOrThrow = function(int $answer): int { - if ($answer !== 42) { - throw new RuntimeException("Unlucky!"); - } - return $answer + 624; -}; - -TrySafe::fromCallable(fn() => $getTheUltimateAnswerOrThrow(true)) - ->flatMap(fn (int $answer) => TrySafe::fromCallable(fn() => $makeTheAnswerBiggerOrThrow($answer))) - ->resolve ( - function(Throwable $e): void { - print $e->getMessage(); - }, - function(int $biggerAnswer): void { - print "The ultimate answer is {$biggerAnswer}"; - } - ); -``` - -_Disclaimer:_ As you probably noticed, we reflect possible exception in return type now, but on the other side, we've lost the information that wrapped success value is `float`. This applies also to `Option`, `ArrayList` etc. Unfortunately there is no silver bullet solution, until PHP have the generics implemented (but hey, have look at [phpstan generics templates](https://medium.com/@ondrejmirtes/generics-in-php-using-phpdocs-14e7301953)). - -#### TrySafe recovery - -We have already learned, that `TrySafe` can be used for chaining dependent operations that can fail (via `flatMap`). How about if we want to have some fallback / recovery in the middle of that chain? - -This is where `recover*` methods come in handy. Let's take a look at this example: - -```php -/** @var callable(Throwable): TrySafe */ -$recovery = fn (Throwable $ex): TrySafe => $backupApi->findGps($query); - -/** @var TrySafe */ -$distance = $api - ->findGps($query) - ->recoverWith($findGpsFromBackupApi) - ->map(fn (Gps $gps) => $this->getDistance($home)); -``` - -There are four `recover*` methods: -- `recover` - Use it to recover with value directly -- `recoverWith` - Use it to recover with value wrapped in `TrySafe`. That allows chaining multiple `failure` recoveries, likewise `flatMap` does for `success`. -- `recoverIf` - Same as `recover`, except it recovers failure only if passed predicate evaluates to true. -- `recoverWithIf` - Same as `recoverWith`, except it recovers failure only if passed predicate evaluates to true. - -```php -/** @var callable(Throwable): TrySafe */ -$recovery = fn (Throwable $ex): TrySafe => $backupApi->findGps($query); - -/** @var TrySafe */ -$distance = $api - ->findGps($query) - ->recoverWithIf( - fn (Throwable $ex) => $ex instanceof ConnectionFailure, // recovers only if first api is down - $findGpsFromBackupApi, - ) - ->recoverIf( - fn (Throwable $ex) => $ex instanceof MalformedQuery, // rather the recovery it keeps as more specific failure - fn (Throwable $ex) => throw new CannotGetGps("Query $query was malformed", 0, $ex), - ) - ->map(fn (Gps $gps) => $this->getDistance($home)); -``` - ### Lift operator Lifting function into (applicative) context means transforming it so it can operate on values wrapped in that context. diff --git a/docs/try-safe.md b/docs/try-safe.md new file mode 100644 index 0000000..6c41d85 --- /dev/null +++ b/docs/try-safe.md @@ -0,0 +1,112 @@ +# TrySafe + +What [`Option`](./option.md) is for possible missing (nullable) values, `TrySafe` is for possible exceptions. + +Traditional way of throwing exceptions and catching them somewhere may obscure that the code can fail. +`TrySafe` is designed (among other things) to be explicit about it on type level. + +## Example +Consider the following code: +```php +interface IntegerParser { + public function parse(mixed $input): int; +} +``` +For well-behaved inputs it will return `int` according to return type declaration. +Until we pass something that we cannot parse. + +As you would guess, `parse` will throw some `Exception` when parsing fails. +We can "improve" the code a little with explicit `@throws` php doc annotation, +but that's about it. Nothing forces us to somehow handle the exceptional case on client side. + +Even typical static analysis don't care too much, because there is nothing like "checked exceptions" +(like in Java). + +```php +$result = IntegerParser::parse("123") + IntegerParse::parse("foo"); +``` + +Another problem is, that it fails only "sometime". +Conditional failing is hell for debugging, it is easier to debug something, +that fails always if not handled correctly. + +Let's see how `TrySafe` can help + +```php +use Bonami\Collection\TrySafe; + +interface IntegerParser { + /** + * @param mixed $input + * @return TrySafe + */ + public function parse(mixed $input): TrySafe; +} +``` + +This time we know, that parsing can fail directly from signature. What's better, +we cannot access the int directly without handling possible failure as well! + +```php +$result = IntegerParser::parse("123") + ->flatMap(fn (int $a) => IntegerParse::parse("foo")->map(fn (int $b) => $a + $b)); +``` + +The example above does not look that much pretty at first glance +(when we need to treat multiple instances of `TrySafe`). + +Fortunately we have more ways of writing this. For example this way: +```php +use Bonami\Collection\ArrayList; +use Bonami\Collection\identity; + +$result = ArrayList::of("123", "foo") + ->flatMap(IntegerParse::parse(...)) + ->sum(identity()); +``` + +Or this way: +```php +use Bonami\Collection\TrySafe; + +$result = TrySafe::lift2(fn (int $a, int $b) => $a + $b)( + IntegerParser::parse("123"), + IntegerParser::parse("foo"), +); +``` + +## Recovery + +We have already learned, that `TrySafe` can be used for chaining dependent operations that can fail (via `flatMap`). +How about having some fallback / recovery in the middle of that chain? + +This is where `recover*` methods come in handy. Let's take a look at this example: + +```php +/** @var TrySafe */ +$distance = $api + ->findGps($query) + ->recoverWith(fn (Throwable $ex): TrySafe => $backupApi->findGps($query)) + ->map(fn (Gps $gps) => $this->getDistance($home)); +``` + +There are four `recover*` methods: +- `recover` - Use it to recover with value directly +- `recoverWith` - Use it to recover with value wrapped in `TrySafe`. That allows chaining multiple `failure` recoveries, likewise `flatMap` does for `success`. +- `recoverIf` - Same as `recover`, except it recovers failure only if passed predicate evaluates to true. +- `recoverWithIf` - Same as `recoverWith`, except it recovers failure only if passed predicate evaluates to true. + +```php +/** @var TrySafe */ +$distance = $api + ->findGps($query) + ->recoverWithIf( + fn (Throwable $ex) => $ex instanceof ConnectionFailure, // recovers only if first api is down + fn (Throwable $ex): TrySafe => $backupApi->findGps($query), + ) + ->recoverIf( + fn (Throwable $ex) => $ex instanceof MalformedQuery, // rather the recovery it keeps as more specific failure + fn (Throwable $ex) => throw new CannotGetGps("Query $query was malformed", 0, $ex), + ) + ->map(fn (Gps $gps) => $this->getDistance($home)); +``` From 4275a9ca9cd6df9b8e1b7fbe885ba8af0cf59b8f Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 21 Jan 2022 17:29:39 +0100 Subject: [PATCH 25/28] fixup! Separate and update Option doc into own file --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index d3fcdcf..1dffa34 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ - [Structures](#structures) - [Type safety](#type-safety) - [Currying](#currying) - - [Option](#option) - [TrySafe](#trysafe) - [Lift operator](#lift-operator) - [Traverse](#traverse) From bec8bb880426d040e030a6c1b168a8d42b478ee4 Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 21 Jan 2022 17:29:48 +0100 Subject: [PATCH 26/28] fixup! Separate and update TrySafe doc --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 1dffa34..1b6aa32 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ - [Structures](#structures) - [Type safety](#type-safety) - [Currying](#currying) - - [TrySafe](#trysafe) - [Lift operator](#lift-operator) - [Traverse](#traverse) - [Type classes](./docs/type-classes.md) From 2dd5ef279caea0fd09a6ff1864a800c761f2f4bf Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 21 Jan 2022 17:30:05 +0100 Subject: [PATCH 27/28] fixup! fixup! Update doc for function currying --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1b6aa32..238f18a 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,10 @@ - [Features](#features) - [Structures](#structures) - [Type safety](#type-safety) - - [Currying](#currying) - [Lift operator](#lift-operator) - [Traverse](#traverse) - [Type classes](./docs/type-classes.md) +- [Currying](./docs/curried-function.md) - [License](#features) - [Contributing](#features) From e7f46f26a4a46f3a8d9dfe2da5267e375bf8c3ab Mon Sep 17 00:00:00 2001 From: Jan Machala Date: Fri, 21 Jan 2022 17:59:29 +0100 Subject: [PATCH 28/28] Separate lift into own document --- README.md | 78 ++++----------------------------------------------- docs/lift.md | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 73 deletions(-) create mode 100644 docs/lift.md diff --git a/README.md b/README.md index 238f18a..76cc9e5 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,11 @@ - [Features](#features) - [Structures](#structures) - [Type safety](#type-safety) - - [Lift operator](#lift-operator) - - [Traverse](#traverse) -- [Type classes](./docs/type-classes.md) -- [Currying](./docs/curried-function.md) +- Advanced topics: + - [Type classes](./docs/type-classes.md) + - [Lift operator](./docs/lift.md) + - [Currying](./docs/curried-function.md) + - [Traverse](#traverse) - [License](#features) - [Contributing](#features) @@ -124,75 +125,6 @@ We are using [phpstan](https://phpstan.org/) annotations for better type safety, resolving, we created optional dependency [phpstan-collections](https://github.com/bonami/phpstan-collections), which we strongly suggest installing if you use phpstan. It fixes some type resolving, especially for late static binding. -### Lift operator - -Lifting function into (applicative) context means transforming it so it can operate on values wrapped in that context. - -Example of lifting function into `Option` context: - -```php -use Bonami\Collection\Option; - -// Get our configuration value wrapped in Option, because it can be missing -function getConfig(string $key): Option { - $config = [ - 'host' => "domain.tld", - 'port' => 8080, - ]; - return Option::fromNullable($config[$key] ?? null); -} - -// Our super usefull method accepts string host, int port & returns uri string -$createUri = fn (string $host, int $port): string => "https://{$host}:{$port}"; - -// Unfortunately our string & int are wrapped in Option context, what now? -$hostOption = getConfig('host'); -$portOption = getConfig('port'); - -// Lifting method will allow to pass values wrapped in Option! -$createUriLifted = Option::lift($createUri); - -// Return value is wrapped in Option too -print $createUriLifted($hostOption, $portOption); // Some(https://domain.tld:8080) -``` - -Please note, that `None` behaves very greedily here - if any of arguments passed into lifted function is `None` the result will be `None` too. Lifting function into `TrySafe` context works analogously. - -As we said earlier `Option` & `ArrayList` are very look-alike. Both can represent that value is missing or present and on top of that `ArrayList` can represent that there is more than one value. We can do some pretty sick tricks using function lifted in `ArrayList` (`LazyList`) context: - -```php -use Bonami\Collection\ArrayList; - -$hosts = ArrayList::fromIterable(['foo.org', 'bar.io']); -$ports = ArrayList::fromIterable([80, 8080]); - -$createUri = fn (string $host, int $port): string => "https://{$host}:{$port}"; - -// Accepts list of strings, list of ints & returns list of uris created from all possible combinations -$createUriLifted = ArrayList::lift($createUri); - -print $createUriLifted($hosts, $ports); // [https://foo.org:80, https://bar.io:80, https://foo.org:8080, https://bar.io:8080] - -``` - -Lifted function generates all possible combinations of hosts & ports for us, which can be very handy! - -Please note that empty `ArrayList` would behave the same way as `None` in `Option` context: -```php -use Bonami\Collection\ArrayList; - -$hosts = ArrayList::fromIterable(['foo.org', 'bar.io']); -$ports = ArrayList::fromEmpty(); - -$createUri = fn (string $host, int $port): string => "https://{$host}:{$port}"; - -$createUriLifted = ArrayList::lift($createUri); - -print $createUriLifted($hosts, $ports); // [] - -``` -This is not coincidence - `Option::none()`, `ArrayList::fromEmpty()`, `LazyList::fromEmpty()`, `TrySafe::failure($ex)` they all create an instance expressing nonexistence of value and are analogous to zero in context of multiplication (empty set in cartesian product for these type classes actually). - ### Traverse You may find yourself in situation, where you map list using mapper function which returns values wrapped in `Option` but you'd rather have values unwrapped. And that is when `traverse` method comes handy: diff --git a/docs/lift.md b/docs/lift.md new file mode 100644 index 0000000..c4f00de --- /dev/null +++ b/docs/lift.md @@ -0,0 +1,79 @@ +# Lift operator + +Lifting function into (applicative) context means transforming it so it can operate on values wrapped in that context. + +## Example +Example of lifting function into `Option` context: + +```php +use Bonami\Collection\Option; + +// Get our configuration value wrapped in Option, because it can be missing +function getConfig(string $key): Option { + $config = [ + 'host' => "domain.tld", + 'port' => 8080, + ]; + return Option::fromNullable($config[$key] ?? null); +} + +// Our super useful method accepts string host, int port & returns uri string +$createUri = fn (string $host, int $port): string => "https://{$host}:{$port}"; + +// Unfortunately our string & int are wrapped in Option context, what now? +$hostOption = getConfig('host'); +$portOption = getConfig('port'); + +// Lifting method will allow to pass values wrapped in Option! +$createUriLifted = Option::lift2($createUri); + +// Return value is wrapped in Option too +print $createUriLifted($hostOption, $portOption); // Option::some("https://domain.tld:8080") +``` + +Please note, that `None` behaves very greedily here - if any of arguments passed into +lifted function is `None` the result will be `None` too. +Lifting function into `TrySafe` context works analogously. + +As we said elsewhere `Option` & `ArrayList` are very look-alike. +Both can represent that value is missing or present and on top of that `ArrayList` +can represent that there is more than one value. +We can do some pretty sick tricks using function lifted in `ArrayList` (`LazyList`) context: + +```php +use Bonami\Collection\ArrayList; + +$hosts = ArrayList::fromIterable(['foo.org', 'bar.io']); +$ports = ArrayList::fromIterable([80, 8080]); + +$createUri = fn (string $host, int $port): string => "https://{$host}:{$port}"; + +// Accepts list of strings, list of ints & returns list of uris created from all possible combinations +$createUriLifted = ArrayList::lift($createUri); + +print $createUriLifted($hosts, $ports); // [https://foo.org:80, https://bar.io:80, https://foo.org:8080, https://bar.io:8080] + +``` + +Lifted function generates all possible combinations of hosts & ports for us, which can be very handy! + +Please note that empty `ArrayList` would behave the same way as `None` in `Option` context: +```php +use Bonami\Collection\ArrayList; + +$hosts = ArrayList::fromIterable(['foo.org', 'bar.io']); +$ports = ArrayList::fromEmpty(); + +$createUri = fn (string $host, int $port): string => "https://{$host}:{$port}"; + +$createUriLifted = ArrayList::lift($createUri); + +print $createUriLifted($hosts, $ports); // [] +``` + +This is not coincidence - `Option::none()`, `ArrayList::fromEmpty()`, `LazyList::fromEmpty()`, `TrySafe::failure($ex)`, `Either::left($error)` +they all create an instance expressing nonexistence of value and are analogous to zero in context of multiplication +(empty set in cartesian product for these type classes actually). + +All this "common" behavior is similar, because they are all Monads and uses `Applicative` and `Monad` traits. +For more information see [type classes](./type-classes.md) doc