Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
19
Help us understand the problem. What is going on with this article?

More than 5 years have passed since last update.

@tadsan

Functoolsで過剰にスマートなPHPを書こう (無名再帰篇)

こんにちは! 一年ほど前に作ったPHPのための函数プログラミング用ライブラリTeto Functoolsの利用者が全然増えないので、信者利用者を増やすために、べんり機能を紹介します。

インストール方法

はじめにDownload Composerを読んでcomposerをインストールしてね。

そして、Functoolsをインストール。

composer global require zonuexe/functools

既存のPHPライブラリに組込むにはこうします。

composer require zonuexe/functools

とりあえずglobal指定でインストールしたことを前提にコード書くよ。

無名再帰とは

無名再帰は、無名函数(ラムダ式とも呼ばれる)を使って再帰することだよ。具体的には不動点コンビネータってテクニックを利用するんだ。その中でも一番有名なのが「Yコンビネータ」だよ。ネットビジネスやベンチャーについて興味のあるひとはY Combinatorを知ってるはずだけど、このベンチャーキャピタルを率ゐるポール・グレアムは有名なLisperなんだ。

Haskell/不動点と再帰 - Wikibooksによれば、Haskellではfixって名前らしいから、恥も外聞もなくぱくってきたよ。カッコイイ用語に酔って中二心が溢れ出してきたのでYコンビネータを実装しようと思ったけど、Teto\Functools::fix()で採用されてるのは正確には正格評価の言語でも利用可能なよう変形した「Zコンビネータ」だよ。正格だけにね!

無名再帰のやりかた

PHPでショートコーディングしたいと思ふじゃないですか。

<?php
($f = function ($n, $max) use (&$f){
    if ($n <= $max) {
        printf("%dは%s".PHP_EOL, $n, ($n % 2 === 0) ? "偶数" : "奇数");
        $f($n + 1, $max);
    }
})(1, 20);

↑ このコードはPHP7では動くけど、PHP5系ではSyntax errorなんだ…!

<?php
use Teto\Functools as f;
require_once getenv('HOME') . '/.composer/vendor/autoload.php';

call_user_func(f::fix(function ($f) {
    return function ($n, $max) use ($f){
        if ($n <= $max) {
            printf("%dは%s".PHP_EOL, $n, ($n % 2 === 0) ? "偶数" : "奇数");
            $f($n + 1, $max);
        }
    };
}), 1, 20);

これでPHP5でも式プログラミングができるぞ! ついでに、見すぼらしい$f =も消えて超ハッピー。

無名再帰の活用例

ズンドコキヨシ with PHP - Qiitaを見たら触発されたので書いてみたよ。

<?php
use Teto\Functools as f;
require_once getenv('HOME') . '/.composer/vendor/autoload.php';

call_user_func(f::fix(function ($func) {
    $zundoco = function () {
        static $zundoco = ['ズン', 'ドコ'];
        return $zundoco[mt_rand(0, 1)];
    };

    static $pattern = ['ズン', 'ズン', 'ズン', 'ズン', 'ドコ'];
    return function (array $a) use ($zundoco, $pattern, &$func) {
        $len = count($a);
        if (isset($a[$len - 1])) {
            echo $a[$len - 1], PHP_EOL;
        }
        if ($a === $pattern) {
            echo 'キ・ヨ・シ!', PHP_EOL;
        } else {
            $func(array_merge(
                ((count($pattern) > $len) ? $a : array_slice($a, 1)),
                [$zundoco()]
            ));
        }
    };
}), []);
19
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
19
Help us understand the problem. What is going on with this article?