Why does my function composition implemented by reduce returns a closure?

user6445533

I want to derive a composition function for n-functions from reduce/fold, but it doesn't work as expected:

$id = function ($x) {
  return $x;
};

$comp = function ($f) {
  return function ($g) use ($f) {
    return function ($x) use ($f, $g) {
      return $f($g($x));
    };
  };
};

$fold = function ($f, $acc) {
  return function ($xs) use ($f, &$acc) {
    return array_reduce($xs, $f, $acc);
  };
};

$compn = function($fs) {/* apply $fold here */};

$inc = function ($n) {
  return $n + 1;
};

$fold($comp, $id) ([$inc, $inc, $inc]) (0); // yields a closure instead of 3

I have the same function implemented in Javascript and it works. I use PHP 7.0.8 cli. I don't know much about PHP, so I am probably overlooking something.

Thank you

Your $comp is curried, and of course you discovered PHP's native array_reduce expects the function to accept multiple parameters – a quick application of uncurry takes some of your pain away, but you'll need to read on if you want to see how this can be improved overall ...


in PHP's humble opinion...

Using uncurry does the trick, but you'll probably end up disliking your program if all the functions are defined as $-named variables – I foresee lots of little problems using that style.

PHP has a callable "type" which makes things a little more PHP-ish – user-defined functions (including higher-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 compn with variadic interface works as expected

function compn (...$fs) {
  return fold ('comp', 'identity') ($fs);
}

function inc ($x) {
  return $x + 1;
}

echo compn ('inc', 'inc', 'inc') (0); // 3

But it works with anonymous functions too

$double = function ($x) { return $x + $x; };

echo compn ($double, $double, 'inc') (2); // 12

functional code, modular program

With your functions declared 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 litter you 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 the named functions will provide more helpful stack trace messages as well


relevant but unimportant

PHP has other reasons for adding the callable type, but ones I'm sure that don't concern you as they're OOP-related – eg,

class method calls

// MyClass::myFunc (1);
call_user_func (['MyClass', 'myFunc'], 1);

object method calls

// $me->myfunc (1);
call_user_func ([$me, 'myfunc'], 1);

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

*why* does multiprocessing serialize my function and closure?

Why does it show that my function returns an int when it returns a char*?

Why does my reduce based average function return NaN?

Why does Agda reduce my function application for some arguments but not for others?

Why does my use of javascript's reduce function return "undefined"

Why does the pow function reduce the length of my loop in C

Swift: Reduce Function with a closure

Why does my function only returns the first object from the array

Why wont my closure function work?

Why are the effects of a function inside my closure not persisting?

Why does function composition require parentheses?

Why does calling my home-rolled (reduce) function with a macro affect future calls to the function?

Composition - Why does my element immediately set a Blur on my animation?

Why does my reduce accumulator reset?

Why does the ++ operator not work in my reduce method

Why does this definition returns a function?

Why does passing a closure to function which accepts a function pointer not work?

How does the reduce function work when a function is returned? Would also like to know more about compose and composition

Why does capturing an Arc by move make my closure FnOnce not Fn

Why does function composition compose from right to left in Javascript?

Why does MPI_REDUCE returns a syntax error at compile time?

Swift Closure why does calling function return error?

Why does this Closure require a return at the outer function also?

Why does my function not run?

why does my async function returns undefine while working with mysql2?

Why does my async function that returns a Future<int> stall at await for each?

Why Does Using the Reference Operator(&) After my Function Type Allow me to Modify the Value it Returns?

why does my SQL execute(select exists) function always returns 1?

Why does my VBA function not evaluate the source cell that returns a HYPERLINK based on an IF statement