Your $comp curried , and, of course, you find that PHP native array_reduce expects the function to take several parameters - quickly the uncurry application takes away some of your pain, but you need to read it if you want to see how it can be improved in general. ..
in PHP a humble opinion ...
Using uncurry does the trick, but you will probably end up disliking your program if all functions are defined as $ -name variables - I anticipate a lot of small problems using this style.
PHP has a callable "type" that makes things a little more specific to PHP functions - order functions) should be called using call_user_func and call_user_func_array
namespace my\module; function identity ($x) { return $x; } function comp ($f) { return function ($g) use ($f) { return function ($x) use ($f, $g) { return call_user_func ($f, call_user_func ($g, $x)); }; }; } function uncurry ($f) { return function ($x, $y) use ($f) { return call_user_func (call_user_func ($f, $x), $y); }; } function fold ($f, $acc) { return function ($xs) use ($f, $acc) { return array_reduce ($xs, uncurry ($f), $acc); }; }
Now your variable interface compn working as expected
function compn (...$fs) { return fold ('comp', 'identity') ($fs); } function inc ($x) { return $x + 1; } echo compn ('inc', 'inc', 'inc') (0);
But it also works with anonymous functions.
$double = function ($x) { return $x + $x; }; echo compn ($double, $double, 'inc') (2);
functional code, modular program
With declared functions using function syntax, you can import them into other areas of your program
// single import use function my\module\fold; // aliased import use function my\module\fold as myfold; // multiple imports use function my\module\{identity, comp, compn, fold};
And now you donβt have to throw code with use blocks every time you want to use one of your functions.
// before $compn = function (...$fs) use ($fold, $comp, $id) { return $fold($comp, $id) ($fs); }; // after function compn (...$fs) { return fold ('comp', 'id') ($fs); }
When it comes to debugging, undoubtedly, named functions will provide more useful stack trace messages as well
relevant but inconsequential
PHP has other reasons for adding a callable type, but I'm sure it doesn't concern you, since they are OOP related - for example,
class method call
// MyClass::myFunc (1); call_user_func (['MyClass', 'myFunc'], 1);
object method call
// $me->myfunc (1); call_user_func ([$me, 'myfunc'], 1);