add partial application util
This commit is contained in:
parent
287f07dba6
commit
fd3288a4ad
11
phpunit.xml
11
phpunit.xml
@ -0,0 +1,11 @@
|
|||||||
|
<phpunit bootstrap="tests/bootstrap.php">
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="all">
|
||||||
|
<directory>tests</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites><filter>
|
||||||
|
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||||
|
<directory suffix=".php">src</directory>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
|
</phpunit>
|
53
src/Utils/PartiallyAppliedFunction.php
Normal file
53
src/Utils/PartiallyAppliedFunction.php
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2018 Kacper Donat
|
||||||
|
*
|
||||||
|
* @author Kacper "Kadet" Donat <kacper@kadet.net>
|
||||||
|
*
|
||||||
|
* Full license available in separate LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Kadet\Functional\Utils;
|
||||||
|
|
||||||
|
use const Kadet\Functional\_ as PLACEHOLDER;
|
||||||
|
|
||||||
|
class PartiallyAppliedFunction
|
||||||
|
{
|
||||||
|
protected $callable;
|
||||||
|
protected $arguments = [];
|
||||||
|
|
||||||
|
public function __construct(callable $callable, ...$args)
|
||||||
|
{
|
||||||
|
switch (true) {
|
||||||
|
case $callable instanceof PartiallyAppliedFunction:
|
||||||
|
$this->callable = $callable->callable;
|
||||||
|
$this->arguments = $callable->prepareArguments($args);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$this->callable = $callable;
|
||||||
|
$this->arguments = array_values($args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __invoke(...$args)
|
||||||
|
{
|
||||||
|
$arguments = $this->prepareArguments($args);
|
||||||
|
return ($this->callable)(...$arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function prepareArguments($args)
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
foreach ($this->arguments as $argument) {
|
||||||
|
$result[] = $argument === PLACEHOLDER
|
||||||
|
? array_shift($args)
|
||||||
|
: $argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_merge(
|
||||||
|
array_values($result),
|
||||||
|
array_values($args)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
17
src/Utils/index.php
Normal file
17
src/Utils/index.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2018 Kacper Donat
|
||||||
|
*
|
||||||
|
* @author Kacper "Kadet" Donat <kacper@kadet.net>
|
||||||
|
*
|
||||||
|
* Full license available in separate LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Kadet\Functional;
|
||||||
|
|
||||||
|
use Kadet\Functional\Utils\PartiallyAppliedFunction;
|
||||||
|
|
||||||
|
function partial(callable $callable, ...$args)
|
||||||
|
{
|
||||||
|
return new PartiallyAppliedFunction($callable, ...$args);
|
||||||
|
}
|
@ -7,6 +7,8 @@ use Kadet\Functional\Predicate\AnyOfPredicate;
|
|||||||
use Kadet\Functional\Predicate\ClosurePredicate;
|
use Kadet\Functional\Predicate\ClosurePredicate;
|
||||||
use Kadet\Functional\Predicate\ConstantPredicate;
|
use Kadet\Functional\Predicate\ConstantPredicate;
|
||||||
|
|
||||||
|
require_once __DIR__.'/Utils/index.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $predicate
|
* @param $predicate
|
||||||
*
|
*
|
||||||
@ -57,3 +59,11 @@ function any(...$predicates)
|
|||||||
$predicates = unpack($predicates);
|
$predicates = unpack($predicates);
|
||||||
return new AnyOfPredicate(...array_map(predicate::class, $predicates));
|
return new AnyOfPredicate(...array_map(predicate::class, $predicates));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function symbol($name = null)
|
||||||
|
{
|
||||||
|
$id = random_bytes(64);
|
||||||
|
return sprintf("%s(%s)", $name ?: 'symbol', $id);
|
||||||
|
}
|
||||||
|
|
||||||
|
define(__NAMESPACE__.'\\_', symbol());
|
57
tests/PartialApplicationTest.php
Normal file
57
tests/PartialApplicationTest.php
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2018 Kacper Donat
|
||||||
|
*
|
||||||
|
* @author Kacper "Kadet" Donat <kacper@kadet.net>
|
||||||
|
*
|
||||||
|
* Full license available in separate LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
use \Kadet\Functional as f;
|
||||||
|
use const Kadet\Functional\_;
|
||||||
|
|
||||||
|
function subtract($a, $b) {
|
||||||
|
return $a - $b;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PartialApplicationTest extends \PHPUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
public function testPartialApplicationOfOneArgument()
|
||||||
|
{
|
||||||
|
$applied = f\partial('subtract', 10);
|
||||||
|
|
||||||
|
$this->assertEquals(0, $applied(10));
|
||||||
|
$this->assertEquals(10, $applied(0));
|
||||||
|
$this->assertEquals(20, $applied(-10));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPartialApplicationOfAllArguments()
|
||||||
|
{
|
||||||
|
$applied = f\partial('subtract', 10, 20);
|
||||||
|
|
||||||
|
$this->assertEquals(-10, $applied());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPartialApplicationOfFewArguments()
|
||||||
|
{
|
||||||
|
$applied = f\partial('array_merge', ['a'], ['b'], ['c']);
|
||||||
|
|
||||||
|
$this->assertEquals(['a', 'b', 'c', 'd', 'e'], $applied(['d'], ['e']));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPartialApplicationWithPlaceholders()
|
||||||
|
{
|
||||||
|
$applied = f\partial('array_merge', ['a'], _, ['c']);
|
||||||
|
|
||||||
|
$this->assertEquals(['a', 'd', 'c'], $applied(['d']));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPartialApplicationOfAppliedFunction()
|
||||||
|
{
|
||||||
|
|
||||||
|
$applied = f\partial('array_merge', ['a'], _, ['c']);
|
||||||
|
$double = f\partial($applied, _, ['d']);
|
||||||
|
|
||||||
|
$this->assertEquals(['a', 'b', 'c', 'd', 'e'], $double(['b'], ['e']));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user