first commit

This commit is contained in:
2023-09-12 21:41:04 +02:00
commit 3361a7f053
13284 changed files with 2116755 additions and 0 deletions

View File

@@ -0,0 +1,82 @@
<?php
namespace OTGS\Installer\Collect\Support;
use Closure;
use BadMethodCallException;
trait Macroable {
/**
* The registered string macros.
*
* @var callable[]
*/
protected static $macros = [];
/**
* Register a custom macro.
*
* @param string $name
* @param callable $macro
*
* @return void
*/
public static function macro( $name, callable $macro ) {
static::$macros[ $name ] = $macro;
}
/**
* Checks if macro is registered.
*
* @param string $name
*
* @return bool
*/
public static function hasMacro( $name ) {
return isset( static::$macros[ $name ] );
}
/**
* Dynamically handle calls to the class.
*
* @param string $method
* @param mixed[] $parameters
*
* @return mixed
*
* @throws \BadMethodCallException
*/
public static function __callStatic( $method, $parameters ) {
if ( ! static::hasMacro( $method ) ) {
throw new BadMethodCallException( "Method {$method} does not exist." );
}
if ( static::$macros[ $method ] instanceof Closure ) {
return call_user_func_array( Closure::bind( static::$macros[ $method ], null, static::class ), $parameters );
}
return call_user_func_array( static::$macros[ $method ], $parameters );
}
/**
* Dynamically handle calls to the class.
*
* @param string $method
* @param mixed[] $parameters
*
* @return mixed
*
* @throws \BadMethodCallException
*/
public function __call( $method, $parameters ) {
if ( ! static::hasMacro( $method ) ) {
throw new BadMethodCallException( "Method {$method} does not exist." );
}
if ( static::$macros[ $method ] instanceof Closure ) {
return call_user_func_array( static::$macros[ $method ]->bindTo( $this, static::class ), $parameters );
}
return call_user_func_array( static::$macros[ $method ], $parameters );
}
}

View File

@@ -0,0 +1,148 @@
<?php
namespace OTGS\Installer;
class Collection {
/**
* @var array
*/
private $array;
private function __construct( array $array ) {
$this->array = $array;
}
/**
* @param array $array
*
* @return Collection
*/
public static function of( array $array ) {
return new static( $array );
}
/**
* @param callable $fn
*
* @return Collection
*/
public function filter( callable $fn ) {
return self::of( array_filter( $this->array, $fn ) );
}
/**
* @param callable $fn
*
* @return Collection
*/
public function map( callable $fn ) {
$keys = array_keys( $this->array );
$items = array_map( $fn, $this->array, $keys );
return self::of( array_combine( $keys, $items ) );
}
/**
* Converts array from key => vales to an array of pairs [ key, value ]
* @return Collection
*/
public function entities() {
$toPairs = function ( $value, $key ) { return [ $key, $value ]; };
return $this->map( $toPairs );
}
/**
* @param string $column
*
* @return Collection
*/
public function pluck( $column ) {
return self::of( array_column( $this->array, $column ) );
}
/**
* @param callable $fn
* @param mixed $initial
*
* @return mixed
*/
public function reduce( callable $fn, $initial = 0 ) {
return array_reduce( $this->array, $fn, $initial );
}
/**
* @return Collection
*/
public function values() {
return self::of( array_values( $this->array ) );
}
/**
* @param Collection $other
*
* @return Collection
*/
public function mergeRecursive( array $other ) {
return self::of( array_merge_recursive( $this->array, $other ) );
}
/**
* @param string $key
*
* @return mixed|Collection|NullCollection|
*/
public function get( $key = null ) {
if ( null !== $key ) {
$data = array_key_exists( $key, $this->array ) ? $this->array[ $key ] : null;
if ( is_array( $data ) ) {
return self::of( $data );
} elseif ( is_null( $data ) ) {
return new NullCollection();
}
return $data;
}
return $this->array;
}
public function getOrNull( $key = null ) {
return $this->get( $key );
}
public function contains( $value ) {
return in_array( $value, $this->array, true );
}
public function head() {
if ( count( $this->array ) ) {
$temp = array_values( $this->array );
$result = $temp[0];
if ( is_array( $result ) ) {
return self::of( $result );
}
return $result;
}
return new NullCollection();
}
}
class NullCollection {
public function map( callable $fn ) { return $this; }
public function filter( callable $fn ) { return $this; }
public function head() { return $this; }
public function pluck() { return $this; }
public function get() { return $this; }
public function getOrNull() { return null; }
}

View File

@@ -0,0 +1,297 @@
<?php
namespace OTGS\Installer\FP;
use OTGS\Installer\Collect\Support\Macroable;
use OTGS\Installer\FP\Traits\Functor;
use OTGS\Installer\FP\Traits\Pointed;
use OTGS\Installer\FP\Traits\ConstApplicative;
use OTGS\Installer\FP\Traits\Applicative;
/**
* Class Either
* @package WPML\FP
*
* @method static callable|Right of( ...$value ) - Curried :: a → Right a
*
* @method static callable|Left left( ...$value ) - Curried :: a → Left a
*
* @method static callable|Right right( ...$value ) - Curried :: a → Right a
*
* @method static callable|Left|Right fromNullable( ...$value ) - Curried :: a → Either a
*
* @method static callable|Left|Right fromBool( ...$value ) - Curried :: a → Either a
*
* @method static Either tryCatch( ...$fn ) - Curried :: a → Either a
*
* @method static mixed getOrElse( ...$other )
*/
abstract class Either {
use Functor;
use Macroable;
/**
* @return void
*/
public static function init() {
self::macro( 'of', Right::of() );
self::macro( 'left', Left::of() );
self::macro( 'right', Right::of() );
self::macro( 'fromNullable', curryN( 1, function ( $value ) {
return is_null( $value ) ? self::left( $value ) : self::right( $value );
} ) );
self::macro( 'fromBool', curryN( 1, function ( $value ) {
return (bool) $value ? self::right( $value ) : self::left( $value );
} ) );
}
/**
* @return Either
*/
public function join() {
if ( ! $this->value instanceof Either ) {
return $this;
}
return $this->value->join();
}
/**
* @param callable $fn
*
* @return mixed
*/
abstract public function chain( callable $fn );
/**
* @param callable $leftFn
* @param callable $rightFn
*
* @return Either|Left|Right
*/
abstract public function bichain( callable $leftFn, callable $rightFn);
/**
* @param callable $fn
*
* @return mixed
*/
abstract public function orElse( callable $fn );
abstract public function bimap( callable $leftFn, callable $rightFn );
abstract public function coalesce( callable $leftFn, callable $rightFn );
abstract public function alt( Either $alt );
abstract public function filter( callable $fn );
}
class Left extends Either {
use ConstApplicative;
use Pointed;
/**
* @param callable $fn
*
* @return Either
*/
public function map( callable $fn ) {
return $this; // noop
}
public function bimap( callable $leftFn, callable $rightFn ) {
return Either::left( $leftFn( $this->value ) );
}
/**
* @param callable $leftFn
* @param callable $rightFn
*
* @return Right
*/
public function coalesce( callable $leftFn, callable $rightFn ) {
return Either::of( $leftFn( $this->value ) );
}
/**
* @return void
* @throws \Exception
*/
public function get() {
throw new \Exception( "Can't extract the value of Left" );
}
/**
* @param mixed $other
*
* @return mixed
*/
public function getOrElse( $other ) {
return $other;
}
/**
* @param callable $fn
*
* @return Right
*/
public function orElse( callable $fn ) {
return Either::right( $fn( $this->value ) );
}
/**
* @param callable $fn
*
* @return Either
*/
public function chain( callable $fn ) {
return $this;
}
/**
* @param callable $leftFn
* @param callable $rightFn
*
* @return Either|Left|Right
*/
public function bichain( callable $leftFn, callable $rightFn ) {
return $leftFn( $this->value );
}
/**
* @param mixed $value
*
* @return void
* @throws \Exception
*/
public function getOrElseThrow( $value ) {
throw new \Exception( $value );
}
/**
* @param callable $fn
*
* @return Either
*/
public function filter( callable $fn ) {
return $this;
}
/**
* @param callable $fn
*
* @return Either
*/
public function tryCatch( callable $fn ) {
return $this; // noop
}
public function alt( Either $alt ) {
return $alt;
}
}
class Right extends Either {
use Applicative;
use Pointed;
/**
* @param callable $fn
*
* @return Either
*/
public function map( callable $fn ) {
return Either::of( $fn( $this->value ) );
}
public function bimap( callable $leftFn, callable $rightFn ) {
return $this->map( $rightFn );
}
/**
* @param callable $leftFn
* @param callable $rightFn
*
* @return Right
*/
public function coalesce( callable $leftFn, callable $rightFn ) {
return $this->map( $rightFn );
}
/**
* @param Either $other
*
* @return mixed
*/
public function getOrElse( $other ) {
return $this->value;
}
/**
* @param callable $fn
*
* @return Either
*/
public function orElse( callable $fn ) {
return $this;
}
/**
* @param mixed $value
*
* @return mixed
*/
public function getOrElseThrow( $value ) {
return $this->value;
}
/**
* @param callable $fn
*
* @return Either
*/
public function chain( callable $fn ) {
return $this->map( $fn )->join();
}
/**
* @param callable $leftFn
* @param callable $rightFn
*
* @return Either|Left|Right
*/
public function bichain( callable $leftFn, callable $rightFn ) {
return $rightFn( $this->value );
}
/**
* @param callable $fn
*
* @return Either
*/
public function filter( callable $fn ) {
return Logic::ifElse( $fn, Either::right(), Either::left(), $this->value );
}
/**
* @param callable $fn
*
* @return Either
*/
public function tryCatch( callable $fn ) {
return tryCatch( function () use ( $fn ) {
return $fn( $this->value );
} );
}
public function alt( Either $alt ) {
return $this;
}
}
Either::init();

View File

@@ -0,0 +1,12 @@
<?php
namespace OTGS\Installer\FP;
use OTGS\Installer\Collect\Support\Macroable;
class Fns {
use Macroable;
const __ = '__CURRIED_PLACEHOLDER__';
}

View File

@@ -0,0 +1,43 @@
<?php
namespace OTGS\Installer\FP;
class _Invoker {
/**
* @var string
*/
private $fnName;
/**
* @var mixed[]
*/
private $args = [];
/**
* _Invoker constructor.
*
* @param string $fnName
*/
public function __construct( $fnName ) {
$this->fnName = $fnName;
}
/**
* @param mixed ...$args
*
* @return _Invoker
*/
public function with( ...$args ) {
$this->args = $args;
return $this;
}
/**
* @param mixed $instance
*
* @return mixed
*/
public function __invoke( $instance ) {
return call_user_func_array( [ $instance, $this->fnName ], $this->args );
}
}

View File

@@ -0,0 +1,135 @@
<?php
namespace OTGS\Installer\FP;
use OTGS\Installer\Collect\Support\Macroable;
/**
* @method static callable|bool not( mixed ...$v ) - Curried :: mixed->bool
* @method static callable|bool isNotNull( mixed ...$v ) - Curried :: mixed->bool
* @method static callable|mixed ifElse( ...$predicate, ...$first, ...$second, ...$data ) - Curried :: ( a->bool )->callable->callable->callable
* @method static callable when( ...$predicate, ...$fn ) - Curried :: ( a->bool )->callable->callable
* @method static callable unless( ...$predicate, ...$fn ) - Curried :: ( a->bool )->callable->callable
* @method static callable cond( ...$conditions, ...$fn ) - Curried :: [( a->bool ), callable]->callable
* @method static callable both( ...$a, ...$b, ...$data ) - Curried :: ( a → bool ) → ( a → bool ) → a → bool
* @method static callable|bool allPass( ...$predicates, ...$data ) - Curried :: [( *… → bool )] → ( *… → bool )
* @method static callable|bool anyPass( ...$predicates, ...$data ) - Curried :: [( *… → bool )] → ( *… → bool )
* @method static callable complement( ...$fn ) - Curried :: ( *… → * ) → ( *… → bool )
* @method static callable|mixed defaultTo( ...$a, ...$b ) - Curried :: a → b → a | b
* @method static callable|bool either( ...$a, ...$b ) - Curried :: ( *… → bool ) → ( *… → bool ) → ( *… → bool )
* @method static callable|mixed until ( ...$predicate, ...$transform, ...$data ) - Curried :: ( a → bool ) → ( a → a ) → a → a
* @method static callable|bool propSatisfies( ...$predicate, ...$prop, ...$data ) - Curried :: ( a → bool ) → String → [String => a] → bool
* @method static callable|bool isArray ( ...$a ) - Curried :: a → bool
* @method static callable|bool isMappable ( ...$a ) - Curried :: a → bool
* @method static callable|bool isEmpty( ...$a ) - Curried:: a → bool
* @method static callable|mixed firstSatisfying( ...$predicate, ...$functions, ...$data ) - Curried:: callable->callable[]->mixed->mixed
* @method static callable|bool isTruthy( ...$data ) - Curried:: mixed->bool
*/
class Logic {
use Macroable;
/**
* @return void
*/
public static function init() {
self::macro( 'not', curryN( 1, function ( $v ) { return ! Fns::value( $v ); } ) );
self::macro( 'isNotNull', curryN( 1, pipe( 'is_null', self::not() ) ) );
self::macro( 'ifElse', curryN( 4, function ( callable $predicate, callable $first, callable $second, $data ) {
return $predicate( $data ) ? $first( $data ) : $second( $data );
} ) );
self::macro( 'when', curryN( 3, function ( callable $predicate, callable $fn, $data ) {
return $predicate( $data ) ? $fn( $data ) : $data;
} ) );
self::macro( 'unless', curryN( 3, function ( callable $predicate, callable $fn, $data ) {
return $predicate( $data ) ? $data : $fn( $data );
} ) );
self::macro( 'cond', curryN( 2, function ( array $conditions, $data ) {
foreach ( $conditions as $condition ) {
if ( $condition[0]( $data ) ) {
return $condition[1]( $data );
}
}
} ) );
self::macro( 'both', curryN( 3, function ( callable $a, callable $b, $data ) {
return $a( $data ) && $b( $data );
} ) );
self::macro( 'allPass', curryN( 2, function ( array $predicates, $data ) {
foreach ( $predicates as $predicate ) {
if ( ! $predicate( $data ) ) {
return false;
}
}
return true;
} ) );
self::macro( 'anyPass', curryN( 2, function ( array $predicates, $data ) {
foreach ( $predicates as $predicate ) {
if ( $predicate( $data ) ) {
return true;
}
}
return false;
} ) );
self::macro( 'complement', curryN( 1, function ( $fn ) {
return pipe( $fn, self::not() );
} ) );
self::macro( 'defaultTo', curryN( 2, function ( $default, $v ) {
return is_null( $v ) ? $default : $v;
} ) );
self::macro( 'either', curryN( 3, function ( callable $a, callable $b, $data ) {
return $a( $data ) || $b( $data );
} ) );
self::macro( 'until', curryN( 3, function ( $predicate, $transform, $data ) {
while ( ! $predicate( $data ) ) {
$data = $transform( $data );
}
return $data;
} ) );
self::macro( 'propSatisfies', curryN( 3, function ( $predicate, $prop, $data ) {
return $predicate( Obj::prop( $prop, $data ) );
} ) );
self::macro( 'isArray', curryN( 1, function( $a ) {
return is_array( $a );
}));
self::macro( 'isMappable', curryN( 1, function( $a ) {
return self::isArray( $a ) || ( is_object( $a ) && method_exists( $a, 'map' ) );
}));
self::macro( 'isEmpty', curryN( 1, function ( $arg ) {
if ( is_array( $arg ) || $arg instanceof \Countable ) {
return count( $arg ) === 0;
}
return empty( $arg );
} ) );
self::macro( 'firstSatisfying', curryN( 3, function ( $predicate, array $conditions, $data ) {
foreach ( $conditions as $condition ) {
$res = $condition( $data );
if ( $predicate( $res ) ) {
return $res;
}
}
return null;
} ) );
self::macro( 'isTruthy', curryN( 1, function ( $data ) {
return $data instanceof \Countable ? count( $data ) > 0 : (bool) $data;
} ) );
}
}
Logic::init();

View File

@@ -0,0 +1,94 @@
<?php
namespace OTGS\Installer\FP;
use OTGS\Installer\Collection;
use OTGS\Installer\NullCollection;
use OTGS\Installer\Collect\Support\Macroable;
/**
* @method static callable|mixed prop( ...$key, ...$obj ) - Curried :: string->Collection|array|object->mixed|null
* @method static callable|mixed propOr( ...$default, ...$key, ...$obj ) - Curried :: mixed->string->Collection|array|object->mixed|null
* @method static callable|mixed path( ...$path, ...$obj ) - Curried :: array->Collection|array|object->mixed|null
* @method static callable|mixed pathOr( ...$default, ...$path, ...$obj ) - Curried :: mixed → array → Collection|array|object → mixed
* @method static callable|bool has( ...$prop, ...$item ) - Curried :: string → a → bool
* @method static callable|bool hasPath( ...$path, ...$item ) - Curried :: array<string> → a → bool
*/
class Obj {
use Macroable;
/**
* @return void
*/
public static function init() {
self::macro( 'prop', curryN( 2, function ( $key, $item ) {
return self::propOr( null, $key, $item );
} ) );
self::macro( 'propOr', curryN( 3, function ( $default, $key, $item ) {
if ( $item instanceof Collection && $item->get( $key ) instanceof NullCollection ) {
return $default;
}
if ( is_array( $item ) ) {
return array_key_exists( $key, $item ) ? $item[ $key ] : $default;
}
if ( is_object( $item ) ) {
if ( property_exists( $item, $key ) || isset( $item->$key ) ) {
return $item->$key;
} elseif ( is_numeric( $key ) ) {
return self::propOr( $default, $key, (array) $item );
} else {
return $default;
}
}
if ( is_null( $item ) ) {
return null;
}
throw( new \InvalidArgumentException( 'item should be a Collection or an array or an object' ) );
} ) );
self::macro( 'path', curryN( 2, function ( $path, $item ) {
return array_reduce( $path, flip( self::prop() ), $item );
} ) );
self::macro( 'pathOr', curryN( 3, function ( $default, $path, $item ) {
$result = Either::of( $item )
->tryCatch( Obj::path( $path ) )
->getOrElse( null );
return is_null( $result ) ? $default : $result;
} ) );
self::macro( 'hasPath', curryN( 2, function ( $path, $item ) {
$undefinedValue = new Undefined();
$currentElement = $item;
foreach ( $path as $pathProp ) {
$currentElement = Either::of( $currentElement )
->tryCatch( self::propOr( $undefinedValue, $pathProp ) )
->getOrElse( $undefinedValue );
if ( $undefinedValue === $currentElement ) {
return false;
}
}
return true;
} ) );
self::macro( 'has', curryN( 2, function ( $prop, $item ) {
if ( $item instanceof Collection ) {
return $item->has( $prop );
}
if ( is_array( $item ) ) {
return isset( $item[ $prop ] );
}
if ( is_object( $item ) ) {
return property_exists( $item, $prop );
}
throw( new \InvalidArgumentException( 'item should be a Collection or an array or an object' ) );
} ) );
}
}
Obj::init();

View File

@@ -0,0 +1,69 @@
<?php
namespace OTGS\Installer\FP;
use OTGS\Installer\Collect\Support\Macroable;
/**
* @method static callable|bool equals( ...$a, ...$b ) - Curried :: a->b->bool
* @method static callable|bool lt( ...$a, ...$b ) - Curried :: a->b->bool
* @method static callable|bool lte( ...$a, ...$b ) - Curried :: a->b->bool
* @method static callable|bool gt( ...$a, ...$b ) - Curried :: a->b->bool
* @method static callable|bool gte( ...$a, ...$b ) - Curried :: a->b->bool
* @method static callable|bool propEq( ...$prop, ...$value, ...$obj ) - Curried :: String → a → array → bool
* @method static callable|array sortWith( ...$comparators, ...$array ) - Curried :: [(a, a) → int] → [a] → [a]
*/
class Relation {
use Macroable;
/**
* @return void
*/
public static function init() {
self::macro( 'equals', curryN( 2, function ( $a, $b ) {
return $a === $b;
} ) );
self::macro( 'lt', curryN( 2, function ( $a, $b ) {
if ( is_string( $a ) && is_string( $b ) ) {
return strcmp( $a, $b ) < 0;
}
return $a < $b;
} ) );
self::macro( 'gt', curryN( 2, function ( $a, $b ) {
return self::lt( $b, $a );
} ) );
self::macro( 'lte', curryN( 2, function ( $a, $b ) {
return ! self::gt( $a, $b );
} ) );
self::macro( 'gte', curryN( 2, function ( $a, $b ) {
return ! self::lt( $a, $b );
} ) );
self::macro( 'propEq', curryN( 3, function ( $prop, $value, $obj ) {
return Obj::prop( $prop, $obj ) === $value;
} ) );
self::macro( 'sortWith', curryN( 2, function ( $comparators, $array ) {
$compareFn = function( $a, $b ) use ( $comparators ) {
foreach ( $comparators as $comparator ) {
$v = $comparator( $a, $b );
if ( $v !== 0 ) {
return $v;
}
}
return 0;
};
return Lst::sort( $compareFn, $array );
}));
}
}
Relation::init();

View File

@@ -0,0 +1,21 @@
<?php
namespace OTGS\Installer\FP;
use OTGS\Installer\Collect\Support\Macroable;
/**
* @method static callable|string len( ...$str ) - Curried :: string → int
*/
class Str {
use Macroable;
/**
* @return void
*/
public static function init() {
self::macro( 'len', curryN( 1, function_exists( 'mb_strlen' ) ? 'mb_strlen' : 'strlen' ) );
}
}
Str::init();

View File

@@ -0,0 +1,14 @@
<?php
namespace OTGS\Installer\FP\Traits;
trait Applicative {
/**
* @param mixed $otherContainer
*
* @return mixed
*/
public function ap( $otherContainer ) {
return $otherContainer->map( $this->value );
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace OTGS\Installer\FP\Traits;
trait ConstApplicative {
/**
* @param mixed $otherContainer
*
* @return mixed
*/
public function ap( $otherContainer ) {
return $this;
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace OTGS\Installer\FP\Traits;
trait Functor {
/** @var mixed */
protected $value;
/**
* @param mixed $value
*/
public function __construct( $value ) {
$this->value = $value;
}
/**
* @return mixed
*/
public function get() {
return $this->value;
}
/**
* @param callable $callback
*
* @return \WPML\FP\Either
*/
abstract public function map( callable $callback );
}

View File

@@ -0,0 +1,25 @@
<?php
namespace OTGS\Installer\FP\Traits;
use function OTGS\Installer\FP\curryN;
trait Pointed {
/**
* of :: a -> M a
*
* Curried function that returns an instance of the derived class
*
* @param mixed $value (optional)
*
* @return mixed|callable
*/
public static function of( $value = null ) {
$of = function ( $value ) {
return new static( $value );
};
return call_user_func_array( curryN( 1, $of ), func_get_args() );
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace OTGS\Installer\FP;
/**
* Class Undefined
* @package OTGS\Installer\FP
*
* Class represents Undefined value. It let us handle correctly expected, but falsy values like null, 0 or false.
*/
class Undefined {
}

View File

@@ -0,0 +1,166 @@
<?php
namespace OTGS\Installer\FP;
/**
* Returns new function which will behave like $function with
* predefined left arguments passed to partial
*
* @param callable $function
* @param mixed ...
*
* @return callable
*/
function partial( callable $function, $dummy ) {
$args = array_slice( func_get_args(), 1 );
return function () use ( $function, $args ) {
return call_user_func_array( $function, array_merge( $args, func_get_args() ) );
};
}
/**
* Returns new function which applies each given function to the result of another from left to right
* pipe(f, g, h)(x) is the same as h(g(f(x)))
*
* @param callable $f
* @param callable $g
*
* @return callable
*/
function pipe( callable $f, callable $g ) {
return call_user_func_array( 'OTGS\Installer\FP\compose', array_reverse( func_get_args() ) );
}
/**
* Returns new function which applies each given function to the result of another from right to left
* compose(f, g, h)(x) is the same as f(g(h(x)))
*
* @param callable $f
* @param callable $g
*
* @return callable
*/
function compose( callable $f, callable $g ) {
$functions = func_get_args();
return function () use ( $functions ) {
$args = func_get_args();
foreach ( array_reverse( $functions ) as $function ) {
$args = array( call_user_func_array( $function, $args ) );
}
return current( $args );
};
}
/**
* @param callable $fn
*
* @return \Closure
*/
function flip( callable $fn ) {
return function () use ( $fn ) {
$args = func_get_args();
if ( count( $args ) > 1 ) {
$temp = $args[0];
$args[0] = $args[1];
$args[1] = $temp;
}
return call_user_func_array( $fn, $args );
};
}
/**
* Wraps the given function and returns a function that can take individual arguments and invokes
* the wrapped function with individual arguments gathered into an array
*
* @param callable $fn
*
* @return \Closure
*/
function gatherArgs( callable $fn ) {
return function ( ...$args ) use ( $fn ) {
return $fn( $args );
};
}
/**
* Returns an Invoker that runs the member function. Use `with` to set the arguments
* of the member function and then invoke with `()`
*
* eg. give Test class:
* class Test {
*
* private $times;
*
* public function __construct( $times ) {
* $this->times = $times;
* }
*
* public function multiply( $x ) {
* return $x * $this->times;
* }
* }
*
* $invoker = invoke( 'multiply' )->with( 10 );
* $result = $invoker( new Test( 2 ) ); // 20
*
*
* @param string $fnName
*
* @return Invoker
*/
function invoke( $fnName ) {
return new Invoker( $fnName );
}
/**
* @param int $count
* @param callable $fn
*
* @return \Closure
*/
function curryN( $count, Callable $fn ) {
$accumulator = function ( array $arguments ) use ( $count, $fn, &$accumulator ) {
return function () use ( $count, $fn, $arguments, $accumulator ) {
$oldArguments = $arguments;
$arguments = array_merge( $arguments, func_get_args() );
$replacementIndex = count( $oldArguments );
for ( $i = 0; $i < $replacementIndex; $i ++ ) {
if ( count( $arguments ) <= $replacementIndex ) {
break;
}
if ( $arguments[ $i ] === Fns::__ ) {
$arguments[ $i ] = $arguments[ $replacementIndex ];
unset( $arguments[ $replacementIndex ] );
$arguments = array_values( $arguments );
}
}
if ( ! in_array( Fns::__, $arguments, true ) && $count <= count( $arguments ) ) {
return call_user_func_array( $fn, $arguments );
}
return $accumulator( $arguments );
};
};
return $accumulator( [] );
}
/**
* @param callable $fn
*
* @return Either
*/
function tryCatch( callable $fn ) {
try {
return Right::of( $fn() );
} catch ( \Exception $e ) {
return Either::left( $e );
}
}