PHP でも関数型っぽく書く
なんとなく表題の事をやってみた。 とりあえず、
- 関数合成
- 部分適用
があればなんとかなりそうなので、作ってみる。
// 関数合成 function compose() { $fns = func_get_args(); $revFns = array_reverse($fns); return function ($initial) use ($revFns) { return array_reduce( $revFns, function ($acc, $fn) { return call_user_func($fn, $acc); }, $initial ); }; } // 部分適用 function partial() { $args = func_get_args(); $fn = array_shift($args); return function () use ($fn, $args) { $newArgs = func_get_args(); $allArgs = array_merge($args, $newArgs); return call_user_func_array($fn, $allArgs); }; }
できたので、いつもの偶数二乗和を求める関数を作ってみる。
// 偶数二乗和を求める
function evenSquareSum($n)
{
// 最後の引数が配列になるように引数の順番を合わせておく
$filter = function ($callback, $array) {
return array_filter($array, $callback);
};
$map = function ($callback, $array) {
return array_map($callback, $array);
};
$reduce = function ($initial, $callback, $array) {
return array_reduce($array, $callback, $initial);
};
// 配列を一つ受け取り、偶数のみ抽出、各要素を 2 乗する、全ての要素を合計する関数を作成
$selectEven = partial($filter, function ($n) { return $n % 2 == 0; });
$squareEach = partial($map, function ($n) { return $n * $n; });
$sum = partial($reduce, 0, function ($acc, $n) { return $acc + $n; });
// それぞれの関数を合成し、偶数二乗和を計算する関数を作る
$evenSquareSum = compose(
$sum,
$squareEach,
$selectEven
);
$numList = range(1, $n);
return $evenSquareSum($numList);
}
$ret = evenSquareSum(10);
var_dump($ret); // => 220
動いてそう。 これのカリー化バージョン作って比べてみると 部分適用との違いとか分かりやすいかも。