/** * 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); }); }
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; }; });
<?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); });
<?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; }; });