24
23

More than 5 years have passed since last update.

関数型 PHP をオブジェクト指向でつなぐライブラリ Piper 作った

Last updated at Posted at 2014-10-09

PHP 5.3 がリリースされてもう 5 年以上経ちます。
5.3 で無名関数 (Closure) が使えるようになってからは、高階関数を使うなどした関数型っぽいアプローチの可能性が広がりました。
中でも nikic/iter は関数型のコレクション操作を行う上で非常に便利なライブラリです。

ですが、関数を単純にラップする記法では、関数を重ねたときに読みづらく感じる人もいるでしょう。
オブジェクト指向的なメソッドチェインと違って、読み下す順番と、実際の実行順序が逆行するところに原因がある気がします。

以下は 1 から 10 までの数列の全要素を 2 倍してから全て足し合わせる例です。

use function iter\fn\operator;
use function iter\map;
use function iter\range;
use function iter\reduce;

echo reduce(operator('+'), map(operator('*', 2), range(1, 10)), 0), PHP_EOL;
// => 110

言語によってはもっと簡略な記法で関数が定義できたり、より読みやすい記法 (Haskell の中置記法とか) が用意されている場合もありますが、PHP にはそういったものはありません。
(HHVM には Closure の簡略記法がありますね)

というわけでこれをライブラリで解決してみました。

Piper

GitHub: yuya-takeyama/piper

ソースとなる値を関数に適用して、その返り値を次の関数に適用して... というのをメソッドチェインで記述するためのライブラリです。
UNIX のパイプラインのようなイメージです。

使い方

さっきと同じロジックを記述してみましょう。
全ての関数を pipe() メソッドでつないでいきます。

use yuyat\Piper;

use function iter\fn\operator;
use function iter\range;

$result = Piper::from(range(1, 10))
    ->pipe('iter\map', [operator('*', 2)])
    ->pipe(function ($iter) { return reduce(operator('+'), $iter, 0); })
    ->get();

echo $result, PHP_EOL;
// => 110

読み下し順通りに実行されるので、さっきの例より内容を理解しやすいのではないでしょうか。

引数が複数あるときは、pipe() メソッドの第二引数として array で渡すことができます。
パイプラインを通ってくる値は常に最後の引数として渡されます。

Piper をカスタマイズする

デフォルトではインスタンスメソッドは pipe()get() しかありませんが、これを拡張してみます。

<?php
use yuyat\Piper;

use function iter\fn\operator;
use function iter\range;
use function iter\map;
use function iter\reduce;

class IterPiper extends Piper
{
    public function map($fn)
    {
        return new static(map($fn, $this->get()));
    }

    public function reduce($fn, $initial = null)
    {
        return new static(reduce($fn, $this->get(), $initial));
    }
}

$result = IterPiper::from(range(1, 10))
    ->map(operator('*', 2))
    ->reduce(operator('+'), 0)
    ->get();

echo $result, PHP_EOL;
// => 110

map()reduce()Piper のメソッドとして実装し、iter をラップする形で利用しています。
ちょっと ginq っぽくなりましたね。

24
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
23