Example #1
0
/**
 * orL, short for logical or, a stand in for ||
 * @sig ($lhs)->($rhs)-> boolean $z
 * @param mixed $lhs
 * @param mixed $rhs
 * @return boolean|\Closure
 */
function orL($lhs = null, $rhs = null)
{
    // Unwrapped curry to have a smaller stack.
    $_ = __PRIVATE__::placeholder();
    $arity = func_num_args();
    $lhsX = $arity > 0 && $lhs !== $_;
    $rhsX = $arity > 1 && $rhs !== $_;
    if ($lhsX && $rhsX) {
        // Both defined
        // Return the result
        return $lhs || $rhs;
    }
    if ($lhsX) {
        if ($lhs) {
            $alwaysTrue = function ($rhs = null) use(&$alwaysTrue, $_) {
                return func_num_args() !== 0 && $rhs !== $_ ? true : $alwaysTrue;
            };
            return $alwaysTrue;
        }
        $rightDeterminate = function ($rhs = null) use(&$rightDeterminate, $_) {
            return func_num_args() !== 0 && $rhs !== $_ ? (bool) $rhs : $rightDeterminate;
        };
        return $rightDeterminate;
    }
    if ($rhsX) {
        // Is the right hand side defined?
        $indeterminate = function ($lhs = null) use($_, &$indeterminate, $rhs) {
            return func_num_args() !== 0 && $lhs !== $_ ? $lhs || $rhs : $indeterminate;
        };
        return $indeterminate;
    }
    // both are undefined, send a wrapped version of itself. (rare)
    return __PRIVATE__::$instance[orL];
}
Example #2
0
/**
 * Takes a callable, then flips the two next arguments before calling the function
 * @param callable
 * @return \Closure f(a, b, ....z) -> f(b,a, ... z)
 */
function flip(callable $hof)
{
    // Use the variadic internal static form of curry. We don't want to eat the rest of the args.
    return __PRIVATE__::curryGiven([], 2, function (...$args) use($hof) {
        $temp = $args[0];
        $args[0] = $args[1];
        $args[1] = $temp;
        return call_user_func_array($hof, $args);
    });
}
Example #3
0
/**
 * andL, short for logical and, a stand in for &&
 * @sig ($lhs)->($rhs)-> boolean $z
 * @param mixed $lhs
 * @param mixed $rhs
 * @return boolean|\Closure
 */
function andL($lhs = null, $rhs = null)
{
    // Unwrapped curry to have a smaller stack.
    $_ = __PRIVATE__::placeholder();
    $arity = func_num_args();
    $lhsX = $arity > 0 && $lhs !== $_;
    $rhsX = $arity > 1 && $rhs !== $_;
    if ($lhsX && $rhsX) {
        // Both defined
        // Return the result
        return $lhs && $rhs;
    }
    if ($lhsX) {
        // first is defined
        if (!$lhs) {
            // if lhs is false, then the result is always false
            $alwaysFalse = function ($rhs = null) use(&$alwaysFalse, $_) {
                return func_num_args() !== 0 && $rhs !== $_ ? false : $alwaysFalse;
            };
            return $alwaysFalse;
        }
        // Otherwise the value is determined only by the rhs
        $rightDeterminate = function ($rhs = null) use($_, &$rightDeterminate) {
            return func_num_args() !== 0 && $rhs !== $_ ? (bool) $rhs : $rightDeterminate;
        };
        return $rightDeterminate;
    }
    if ($rhsX) {
        // Is the right hand side defined?
        $indeterminate = function ($lhs = null) use($_, &$indeterminate, $rhs) {
            return func_num_args() !== 0 && $lhs !== $_ ? $lhs && $rhs : $indeterminate;
        };
        return $indeterminate;
    }
    // both are undefined, send a wrapped version of itself. (rare)
    return __PRIVATE__::$instance[andL];
}
Example #4
0
<?php

namespace PHPixme;

/**
 * ufo, short for the space ship operator, or the three way comparison, a stand in for <=>
 * @sig ($lhs)->($rhs)-> boolean $z
 * @param mixed $lhs
 * @param mixed $rhs
 * @return int|\Closure
 */
function ufo($lhs = null, $rhs = null)
{
    return call_user_func_array(__PRIVATE__::$instance[ufo], func_get_args());
}
const ufo = __NAMESPACE__ . '\\ufo';
__PRIVATE__::$instance[ufo] = __PRIVATE__::curryExactly2(function ($lhs, $rhs) {
    return $lhs != $rhs ? $lhs > $rhs ? 1 : -1 : 0;
});
Example #5
0
namespace PHPixme;

/**
 * @param callable $hof
 * @param \Traversable= $traversable
 * @return \Closure|mixed
 * @sig Callable (a, b -> a) -> \Traversable[a,b] -> a
 */
function reduceRight($hof = null, $traversable = null)
{
    return call_user_func_array(__PRIVATE__::$instance[reduceRight], func_get_args());
}
const reduceRight = __NAMESPACE__ . '\\reduceRight';
__PRIVATE__::$instance[reduceRight] = __PRIVATE__::curryExactly2(function ($hof, $arrayLike) {
    __CONTRACT__::argIsACallable($hof);
    __CONTRACT__::argIsATraversable($arrayLike, 1);
    if ($arrayLike instanceof ReducibleInterface) {
        return $arrayLike->reduceRight($hof);
    }
    // Equalize the usefulness
    $array = __CONTRACT__::isNonEmpty(__PRIVATE__::traversableToArray($arrayLike));
    $output = end($array);
    $value = prev($array);
    // Traverse using the internal pointer to avoid creating additional work
    while (($key = key($array)) !== null) {
        $output = call_user_func($hof, $output, $value, $key, $arrayLike);
        $value = prev($array);
    }
    return $output;
});
Example #6
0
namespace PHPixme;

/**
 * Takes two functions and has the first consume the output of the second, combining them to a single function
 * @param callable $hofSecond
 * @param callable = $hofFirst
 * @return \Closure
 * @sig (Unary Callable(y -> z), ..., Unary Callable(a -> b), Callable (*->a)) -> \Closure (* -> a)
 */
function combine(callable $hofSecond = null, callable $hofFirst = null)
{
    return call_user_func_array(__PRIVATE__::$instance[combine], func_get_args());
}
const combine = __NAMESPACE__ . '\\combine';
__PRIVATE__::$instance[combine] = __PRIVATE__::curryGiven([], 2, function () {
    $combine = func_get_args();
    foreach ($combine as $idx => $hof) {
        __CONTRACT__::argIsACallable($hof, $idx);
    }
    $combineHead = end($combine);
    $combineTail = array_slice($combine, 0, -1);
    $combineTailSize = count($combineTail);
    return function () use($combineHead, $combineTail, $combineTailSize) {
        $acc = call_user_func_array($combineHead, func_get_args());
        for ($index = $combineTailSize - 1; -1 < $index; $index -= 1) {
            $acc = call_user_func($combineTail[$index], $acc);
        }
        return $acc;
    };
});
Example #7
0
<?php

namespace PHPixme;

/**
 * Group a traversable by a return value, separating them out into [groupName=>[value...]]
 * @param callable $fn
 * @param array|\Traversable $arrayLike
 * @return array|\Closure
 */
function group($fn = null, $arrayLike = null)
{
    return call_user_func_array(__PRIVATE__::$instance[group], func_get_args());
}
const group = __NAMESPACE__ . '\\group';
__PRIVATE__::$instance[group] = __PRIVATE__::curryExactly2(function ($fn, $arrayLike) {
    __CONTRACT__::argIsACallable($fn);
    __CONTRACT__::argIsATraversable($arrayLike, 1);
    if ($arrayLike instanceof GroupableInterface) {
        return $arrayLike->group($fn);
    }
    $output = [];
    foreach (__PRIVATE__::protectTraversable($arrayLike) as $key => $value) {
        $output[call_user_func($fn, $value, $key, $arrayLike)][] = $value;
    }
    return $output;
});
Example #8
0
<?php

namespace PHPixme;

// -- Starling --
/**
 * Starling
 * This combinator takes two functions and applies the third across both.
 * The first operand must return a function, which will relieve the result of the second.
 * Useful for combining mappings of the same data together
 * @param callable $x
 * @param callable $y
 * @param mixed $z
 * @return \Closure|mixed
 * @sig Callable x -> Callable y -> z -> a
 */
function S($x = null, $y = null, $z = null)
{
    return call_user_func_array(__PRIVATE__::$instance[S], func_get_args());
}
const S = __NAMESPACE__ . '\\S';
__PRIVATE__::$instance[S] = __PRIVATE__::curryExactly3(function ($x, $y, $z) {
    __CONTRACT__::argIsACallable($x);
    __CONTRACT__::argIsACallable($y, 1);
    return call_user_func(__CONTRACT__::composedIsACallable(call_user_func($x, $z)), call_user_func($y, $z));
});
Example #9
0
<?php

namespace PHPixme;

/**
 * callWith
 * Produce a function that calls a function within a array or object
 * @param string $accessor
 * @param object|array $container
 * @return \Closure ($container) -> ((args) -> $container{[$accessor]}(...args))
 * @sig String -> Object|Array -> \Closure (*->x)
 */
function callWith($accessor = null, $container = null)
{
    return call_user_func_array(__PRIVATE__::$instance[callWith], func_get_args());
}
const callWith = __NAMESPACE__ . '\\callWith';
__PRIVATE__::$instance[callWith] = __PRIVATE__::curryExactly2(function ($accessor, $container) {
    $callable = __CONTRACT__::composedIsACallable(is_array($container) ? array_key_exists($accessor, $container) ? $container[$accessor] : null : [$container, $accessor]);
    return function () use($callable) {
        return call_user_func_array($callable, func_get_args());
    };
});
Example #10
0
<?php

namespace PHPixme;

/**
 * @param $hofFirst
 * @param callable $hofSecond
 * @return mixed
 * @sig (Callable (* -> a) -> Unary Callable ( a -> b ), ..., Unary Callable (y -> z)) -> \Closure (*->z)
 */
function pipe(callable $hofFirst = null, callable $hofSecond = null)
{
    return call_user_func_array(__PRIVATE__::$instance[pipe], func_get_args());
}
const pipe = __NAMESPACE__ . '\\pipe';
__PRIVATE__::$instance[pipe] = __PRIVATE__::curryGiven([], 2, function ($x) {
    $pipe = func_get_args();
    foreach ($pipe as $index => $value) {
        __CONTRACT__::argIsACallable($value, $index);
    }
    $pipeTail = array_splice($pipe, 1);
    return function () use($x, $pipeTail) {
        $acc = call_user_func_array($x, func_get_args());
        $_pipeTail = $pipeTail;
        foreach ($_pipeTail as $hof) {
            $acc = call_user_func($hof, $acc);
        }
        return $acc;
    };
});
Example #11
0
<?php

/**
 * Created by PhpStorm.
 * User: rgladson
 * Date: 5/12/2016
 * Time: 12:03 PM
 */
namespace PHPixme;

/**
 * Wrap a function in an argument that will eat all but n arguments
 * @param int $arity
 * @param callable = $hof
 * @return \Closure
 * @sig Integer -> Callable (* -> x) -> \Closure (* -> x)
 */
function nAry($arity = null, callable $hof = null)
{
    return call_user_func_array(__PRIVATE__::$instance[nAry], func_get_args());
}
const nAry = __NAMESPACE__ . '\\nAry';
__PRIVATE__::$instance[nAry] = __PRIVATE__::curryExactly2(function ($number = 0, $hof = null) {
    __CONTRACT__::argIsAPositiveOrZeroInt($number);
    __CONTRACT__::argIsACallable($hof, 1);
    return function () use($number, $hof) {
        $args = func_get_args();
        return call_user_func_array($hof, array_slice($args, 0, $number));
    };
});
Example #12
0
<?php

namespace PHPixme;

/**
 * pluckArrayWith
 * Creates a function to access the property of an object
 * @param string $accessor
 * @param array $container
 * @return \Closure ($object) -> object->accessor
 * @sig String -> Array -> \Closure (->x)
 */
function pluckArrayWith($accessor = null, $container = null)
{
    return call_user_func_array(__PRIVATE__::$instance[pluckArrayWith], func_get_args());
}
const pluckArrayWith = __NAMESPACE__ . '\\pluckArrayWith';
__PRIVATE__::$instance[pluckArrayWith] = __PRIVATE__::curryExactly2(function ($accessor, $container) {
    return $container[$accessor];
});
Example #13
0
<?php

namespace PHPixme;

/**
 * xorL, short for logical xor, a stand in for xor keyword
 * @sig ($lhs)->($rhs)-> boolean $z
 * @param mixed $lhs
 * @param mixed $rhs
 * @return boolean|\Closure
 */
function xorL($lhs = null, $rhs = null)
{
    return call_user_func_array(__PRIVATE__::$instance[xorL], func_get_args());
}
const xorL = __NAMESPACE__ . '\\xorL';
__PRIVATE__::$instance[xorL] = __PRIVATE__::curryExactly2(function ($lhs, $rhs) {
    return $lhs xor $rhs;
});
Example #14
0
namespace PHPixme;

/**
 * @param callable $hof
 * @param mixed = $startVal
 * @param \Traversable= $traversable
 * @return \Closure|mixed
 * @sig (Callable (a, b) -> a) -> a -> \Traversable [b] -> a
 */
function foldRight($hof = null, $startVal = null, $traversable = null)
{
    return call_user_func_array(__PRIVATE__::$instance[foldRight], func_get_args());
}
const foldRight = __NAMESPACE__ . '\\foldRight';
__PRIVATE__::$instance[foldRight] = __PRIVATE__::curryExactly3(function ($hof, $startVal, $arrayLike) {
    __CONTRACT__::argIsACallable($hof);
    __CONTRACT__::argIsATraversable($arrayLike, 2);
    if ($arrayLike instanceof FoldableInterface) {
        return $arrayLike->foldRight($hof, $startVal);
    }
    // Use traversableToArray, because right is non-lazy on \Traversable
    $array = __PRIVATE__::traversableToArray($arrayLike);
    $output = $startVal;
    end($array);
    while (!is_null($key = key($array))) {
        $output = call_user_func($hof, $output, current($array), $key, $arrayLike);
        prev($array);
    }
    return $output;
});
Example #15
0
<?php

namespace PHPixme;

/**
 * pluckObjectWith
 * Creates a function to access the property of an object
 * @param string $accessor
 * @param Object $container
 * @return \Closure ($object) -> object->accessor
 * @sig String -> Object -> \Closure (->x)
 */
function pluckObjectWith($accessor = null, $container = null)
{
    return call_user_func_array(__PRIVATE__::$instance[pluckObjectWith], func_get_args());
}
const pluckObjectWith = __NAMESPACE__ . '\\pluckObjectWith';
__PRIVATE__::$instance[pluckObjectWith] = __PRIVATE__::curryExactly2(function ($accessor, $container) {
    return $container->{$accessor};
});
Example #16
0
<?php

namespace PHPixme;

/**
 * @param Callable $decorator
 * @param Callable $fn
 * @return \Closure
 */
function except($decorator = null, $fn = null)
{
    return call_user_func_array(__PRIVATE__::$instance[except], func_get_args());
}
const except = __NAMESPACE__ . '\\except';
__PRIVATE__::$instance[except] = __PRIVATE__::curryExactly2(function ($predicate, $fn) {
    __CONTRACT__::argIsACallable($predicate);
    __CONTRACT__::argIsACallable($fn, 1);
    return function () use($predicate, $fn) {
        $args = func_get_args();
        return call_user_func_array($predicate, $args) ? null : call_user_func_array($fn, $args);
    };
});
Example #17
0
<?php

namespace PHPixme;

/**
 * @param callable $hof
 * @param array|\Traversable|FunctorInterface $traversable
 * @return \Closure|mixed
 * @sig Callable (a -> b) -> \Traversable[a] -> \Traversable[b]
 *
 */
function map($hof = null, $traversable = null)
{
    return call_user_func_array(__PRIVATE__::$instance[map], func_get_args());
}
const map = __NAMESPACE__ . '\\map';
__PRIVATE__::$instance[map] = __PRIVATE__::curryExactly2(function ($hof, $traversable) {
    __CONTRACT__::argIsACallable($hof);
    __CONTRACT__::argIsATraversable($traversable, 1);
    if ($traversable instanceof FunctorInterface) {
        return $traversable->map($hof);
    }
    $output = [];
    foreach (__PRIVATE__::protectTraversable($traversable) as $key => $value) {
        $output[$key] = call_user_func($hof, $value, $key, $traversable);
    }
    return $output;
});
Example #18
0
<?php

namespace PHPixme;

/**
 * Take a callable and produce a curried \Closure
 * @param int $arity
 * @param callable = $hof
 * @return \Closure
 * @sig Integer -> Callable (*-> x) -> \Closure (* -> x)
 */
function curry($arity = null, callable $hof = null)
{
    return call_user_func_array(__PRIVATE__::$instance[curry], func_get_args());
}
const curry = __NAMESPACE__ . '\\curry';
__PRIVATE__::$instance[curry] = __PRIVATE__::curryExactly2(function ($arity, $callable) {
    __CONTRACT__::argIsAPositiveOrZeroInt($arity);
    __CONTRACT__::argIsACallable($callable, 1);
    // The function is static so that is easier to recurse,
    // as it shares no state with itself outside its arguments.
    return __PRIVATE__::curryGiven([], $arity, $callable);
});
Example #19
0
<?php

namespace PHPixme;

/**
 * After Decorator
 * Decorate a callable using the return value of the decorated callable as the argument
 * for this decorative function. It does not modify the return value.
 * @param Callable $decorator
 * @param Callable $fn
 * @return \Closure
 * @sig Callable (x->) -> Callable (*->x) -> Closure (*->x)
 */
function after($decorator = null, $fn = null)
{
    return call_user_func_array(__PRIVATE__::$instance[after], func_get_args());
}
const after = __NAMESPACE__ . '\\after';
__PRIVATE__::$instance[after] = __PRIVATE__::curryExactly2(function ($decorator, $fn) {
    __CONTRACT__::argIsACallable($decorator);
    __CONTRACT__::argIsACallable($fn, 1);
    return function () use($decorator, $fn) {
        $value = call_user_func_array($fn, func_get_args());
        call_user_func($decorator, $value);
        return $value;
    };
});
Example #20
0
<?php

namespace PHPixme;

/**
 * notB, not binary, invert, or 2's compliment, a stand in for ~
 * @sig (int $rhs) -> int $z
 * @param int $rhs
 * @return int|\Closure
 */
function notB($rhs = null)
{
    return call_user_func_array(__PRIVATE__::$instance[notB], func_get_args());
}
const notB = __NAMESPACE__ . '\\notB';
__PRIVATE__::$instance[notB] = __PRIVATE__::curryExactly1(function ($rhs) {
    return ~$rhs;
});
Example #21
0
<?php

namespace PHPixme;

/**
 * Before decorator
 * Wraps a Closure around a callable, running the decorating callable with the same arguments
 * before executing and returning the value of the decorated function
 * @param Callable $decorator
 * @param Callable $fn
 * @return \Closure
 * @sig Callable (*->) -> Callable (*->x) -> Closure (*->x)
 */
function before($decorator = null, $fn = null)
{
    return call_user_func_array(__PRIVATE__::$instance[before], func_get_args());
}
const before = __NAMESPACE__ . '\\before';
__PRIVATE__::$instance[before] = __PRIVATE__::curryExactly2(function ($decorator, $fn) {
    __CONTRACT__::argIsACallable($decorator);
    __CONTRACT__::argIsACallable($fn, 1);
    return function () use($decorator, $fn) {
        $args = func_get_args();
        call_user_func_array($decorator, $args);
        return call_user_func_array($fn, $args);
    };
});
Example #22
0
<?php

namespace PHPixme;

/**
 * gte, short for greater than or equal to, a stand in for >=
 * @sig ($lhs)->($rhs)-> boolean $z
 * @param mixed $lhs
 * @param mixed $rhs
 * @return boolean|\Closure
 */
function gte($lhs = null, $rhs = null)
{
    return call_user_func_array(__PRIVATE__::$instance[gte], func_get_args());
}
const gte = __NAMESPACE__ . '\\gte';
__PRIVATE__::$instance[gte] = __PRIVATE__::curryExactly2(function ($lhs, $rhs) {
    return $lhs > $rhs;
});
Example #23
0
<?php

namespace PHPixme;

/**
 * map
 * @param callable $hof
 * @param array|FunctorInterface|\Traversable $collection
 * @return \Closure|$collection
 */
function walk($hof = null, $collection = null)
{
    return call_user_func_array(__PRIVATE__::$instance[walk], func_get_args());
}
const walk = __NAMESPACE__ . '\\walk';
__PRIVATE__::$instance[walk] = __PRIVATE__::curryExactly2(function ($hof, $collection) {
    __CONTRACT__::argIsACallable($hof);
    __CONTRACT__::argIsATraversable($collection, 1);
    if ($collection instanceof FunctorInterface) {
        return $collection->walk($hof);
    }
    $array = __PRIVATE__::getArrayFrom($collection);
    if ($array !== null) {
        array_walk($array, $hof, $collection);
    } else {
        foreach (__PRIVATE__::copyTransversable($collection) as $k => $v) {
            call_user_func($hof, $v, $k, $collection);
        }
    }
    return $collection;
});
Example #24
0
<?php

namespace PHPixme;

/**
 * shiftL, or shift left, a stand in for <<
 * @param int|float $lhs
 * @param int $rhs
 * @return int|\Closure
 */
function shiftL($lhs = null, $rhs = null)
{
    return call_user_func_array(__PRIVATE__::$instance[shiftL], func_get_args());
}
const shiftL = __NAMESPACE__ . '\\shiftL';
__PRIVATE__::$instance[shiftL] = __PRIVATE__::curryExactly2(function ($lhs, $rhs) {
    return $lhs << $rhs;
});
Example #25
0
<?php

namespace PHPixme;

/**
 * nid, short for not the identity, or not strictly equals, a stand in for !==
 * @sig ($lhs)->($rhs)-> boolean $z
 * @param mixed $lhs
 * @param mixed $rhs
 * @return boolean|\Closure
 */
function nid($lhs = null, $rhs = null)
{
    return call_user_func_array(__PRIVATE__::$instance[nid], func_get_args());
}
const nid = __NAMESPACE__ . '\\nid';
__PRIVATE__::$instance[nid] = __PRIVATE__::curryExactly2(function ($lhs, $rhs) {
    return $lhs !== $rhs;
});