为什么我的函数组合由reduce实现了一个闭包?

8 php reduce functional-programming function-composition

我想从reduce/fold导出n函数的合成函数,但它不能按预期工作:

$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
Run Code Online (Sandbox Code Playgroud)

我有相同的功能在Javascript中实现,它的工作原理.我使用PHP 7.0.8 cli.我对PHP知之甚少,所以我可能忽略了一些东西.

Tha*_*you 1

$comp柯里化的,当然你发现 PHP 的本机array_reduce期望该函数接受多个参数 \xe2\x80\x93 的快速应用uncurry可以减轻你的一些痛苦,但是如果你想要的话,你需要继续阅读看看如何整体改进......

\n\n
\n\n

以 PHP 的愚见......

\n\n

使用uncurry可以解决问题,但如果所有函数都定义为命名变量 \xe2\x80\x93 ,你可能最终会不喜欢你的程序。$我预见使用这种风格会出现很多小问题。

\n\n

PHP 有一个可调用的“类型”,这使得事情变得更像 PHP \xe2\x80\x93 用户定义的函数(包括高阶函数)应该使用call_user_funccall_user_func_array调用

\n\n
namespace my\\module;\n\nfunction identity ($x) {\n  return $x;\n}\n\nfunction comp ($f) {\n  return function ($g) use ($f) {\n    return function ($x) use ($f, $g) {\n      return call_user_func ($f, call_user_func ($g, $x));\n    };\n  };\n}\n\nfunction uncurry ($f) {\n  return function ($x, $y) use ($f) {\n    return call_user_func (call_user_func ($f, $x), $y);\n  };\n}\n\nfunction fold ($f, $acc) {\n  return function ($xs) use ($f, $acc) {\n    return array_reduce ($xs, uncurry ($f), $acc);\n  };\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在您的compn可变参数界面可以按预期工作

\n\n
function compn (...$fs) {\n  return fold (\'comp\', \'identity\') ($fs);\n}\n\nfunction inc ($x) {\n  return $x + 1;\n}\n\necho compn (\'inc\', \'inc\', \'inc\') (0); // 3\n
Run Code Online (Sandbox Code Playgroud)\n\n

但它也适用于匿名函数

\n\n
$double = function ($x) { return $x + $x; };\n\necho compn ($double, $double, \'inc\') (2); // 12\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

功能代码、模块化程序

\n\n

使用语法声明函数后function,您可以导入程序的其他区域

\n\n
// single import\nuse function my\\module\\fold;\n\n// aliased import\nuse function my\\module\\fold as myfold;\n\n// multiple imports\nuse function my\\module\\{identity, comp, compn, fold};\n
Run Code Online (Sandbox Code Playgroud)\n\n

use现在,每次您想要使用某个函数时,您不必在代码中乱扔-blocks

\n\n
// before\n$compn = function (...$fs) use ($fold, $comp, $id) {\n  return $fold($comp, $id) ($fs);\n};\n\n// after\nfunction compn (...$fs) {\n  return fold (\'comp\', \'id\') ($fs);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在调试方面,毫无疑问,命名函数也会提供更有用的堆栈跟踪消息

\n\n
\n\n

相关但不重要

\n\n

PHP 还有其他原因添加可调用类型,但我确信这些原因与您无关,因为它们与 OOP 相关 \xe2\x80\x93 例如,

\n\n

类方法调用

\n\n
// MyClass::myFunc (1);\ncall_user_func ([\'MyClass\', \'myFunc\'], 1);\n
Run Code Online (Sandbox Code Playgroud)\n\n

对象方法调用

\n\n
// $me->myfunc (1);\ncall_user_func ([$me, \'myfunc\'], 1);\n
Run Code Online (Sandbox Code Playgroud)\n