share apply dispatch with compiled fixed functions

This commit is contained in:
Kacper Donat 2026-10-27 22:11:15 +01:00
parent bdb49b0d78
commit 66705f3e31
2 changed files with 34 additions and 33 deletions

View File

@ -11,10 +11,10 @@ namespace Kadet\Functional\Utils;
use function Kadet\Functional\apply;
use function Kadet\Functional\applyWithArity;
use Kadet\Functional\Compilable;
use function Kadet\Functional\compile;
use Kadet\Functional\Decorator;
use function Kadet\Functional\partial;
use function Kadet\Functional\reflect;
class FixedFunction implements Decorator, Compilable
@ -70,22 +70,7 @@ class FixedFunction implements Decorator, Compilable
$call = $fixed instanceof CurriedFunction ? $fixed : compile($fixed);
$self = static function (...$args) use (&$self, $fixed, $call, $variadic, $required, $all) {
array_unshift($args, $self);
switch (true) {
case $variadic:
return partial($fixed, ...$args);
case count($args) >= $all:
$applied = $call(...array_slice($args, 0, $all));
return is_callable($applied) ? apply($applied, ...array_slice($args, $all)) : $applied;
case count($args) >= $required:
return $call(...$args);
default:
return partial($fixed, ...$args);
}
return applyWithArity($fixed, $call, $variadic, $required, $all, [$self, ...$args]);
};
return $self;

View File

@ -24,29 +24,45 @@ function apply(callable $callable, ...$args)
{
try {
$reflection = reflect($callable);
$required = $reflection->getNumberOfRequiredParameters();
$all = $reflection->getNumberOfParameters();
switch (true) {
case $reflection->isVariadic():
return partial($callable, ...$args);
case count($args) >= $all:
$applied = $callable(...array_slice($args, 0, $all));
return is_callable($applied) ? apply($applied, ...array_slice($args, $all)) : $applied;
case count($args) >= $required:
return $callable(...$args);
default:
return partial($callable, ...$args);
}
return applyWithArity(
$callable,
$callable,
$reflection->isVariadic(),
$reflection->getNumberOfRequiredParameters(),
$reflection->getNumberOfParameters(),
$args
);
} catch (\ReflectionException $exception) {
// if cannot gather necessary information for intelligent application just use normal one
return $callable(...$args);
}
}
/**
* The argument dispatch of apply(), with the arity of $callable already known: it calls $call when there are enough
* arguments and partially applies $callable otherwise.
*
* @internal
*/
function applyWithArity(callable $callable, callable $call, bool $variadic, int $required, int $all, array $args)
{
switch (true) {
case $variadic:
return partial($callable, ...$args);
case count($args) >= $all:
$applied = $call(...array_slice($args, 0, $all));
return is_callable($applied) ? apply($applied, ...array_slice($args, $all)) : $applied;
case count($args) >= $required:
return $call(...$args);
default:
return partial($callable, ...$args);
}
}
function curry(callable $callable, ?int $threshold = null, ...$args): CurriedFunction
{
return new CurriedFunction($callable, $threshold, ...$args);