LoginSignup
9
11

More than 5 years have passed since last update.

PHPでカリー化?なにそれ美味しいの?

Posted at

食べてみたい?

とりあえず既存の関数をカリー化した関数を返す関数というのを作ってみたわけだが。

curry.php
<?php

function curry($fn) {
    $args = func_get_args();
    $fn = array_shift($args);
    if (!is_a($fn, 'ReflectionFunction'))
        $fn = new ReflectionFunction($fn);
    return function() use ($fn, $args) {
        $args = array_merge($args, func_get_args());
        if (count($args) >= $fn->getNumberOfRequiredParameters())
            return $fn->invokeArgs($args);
        else 
            return call_user_func_array(
                'curry', array_merge(array($fn), $args));
    };
}

使い方

<?php

function hoge($a1, $a2, $a3) {
    return $a1 + $a2 + $a3;
}

// 引数を個別渡し
$c0 = curry('hoge');
$c1 = $c0(1);
$c2 = $c1(2);
$ret = $c2(3);

// 複数まとめて
$c0 = curry('hoge');
$c2 = $c0(1, 2);
$ret  = $c2(3);

// 最初の引数を決めうち
$c1 = curry('hoge', 1);
$ret = $c1(2, 3);

// 複数引数決めうち 
$c2 = curry('hoge', 1, 2);
$ret  = $c2(3);

現状、引数の参照渡しには対応していない。(エラーになる)

使用例

<?php

$c = curry('implode');
$csv = $c(',');
$tsv = $c("\t");

$arr = array(1,2,3);
var_dump( $csv($arr));       // string(5) "1,2,3"
var_dump( $tsv($arr));        // string(5) "1   2   3"

<?php

$arr = array(1,2,3);
var_dump( array_map( curry('sprintf', '%04d'), $arr));
/*
array(3) {
  [0]=>
  string(4) "0001"
  [1]=>
  string(4) "0002"
  [2]=>
  string(4) "0003"
}
*/
<?php

$even = curry(function ($m, $v) { return ($v % $m) == 0 ; }, 2);
print_r( array_filter(range(1, 10), $even));
/*
Array
(
    [1] => 2
    [3] => 4
    [5] => 6
    [7] => 8
    [9] => 10
)*/
<?php

$replace_md_link = curry(
    'preg_replace_callback', '/\[(.+?)?\]\((\S+?)(\s+"(.+)")?(\s*?\))/');
$format_link_callback = curry(
    'vsprintf', '<a href="%3$s" title="%5$s">%2$s</a>');
$convert_link = curry($replace_md_link, $format_link_callback);

$markdown = '[ほげぶろぐ](http://example.jp "Hoge Blog!")';
var_dump( $convert_link($markdown));
// => string(66) "<a href="http://example.jp" title="Hoge Blog!">ほげぶろぐ</a>"

<?php

$csv = fopen("sample.csv", 'r');
$read_csv = curry('fgetcsv', $csv);
$fields = $read_csv();  // 1行目がフィールド名
$assoc = curry('array_combine', $fields);

$rset = array();
while($values = $read_csv()) {
    $rset[] = $assoc($values);
}

fclose($csv);
var_dump($rset);

いろいろ頑張ってみたが、あまりうれしい感がない、というかコレジャナイ感がただようのはなぜなのか。

計算機科学的にこれがカリー化と呼べるシロモノなのかは正直自信がない。
本場の味を知る人に聞いてみないとわからないところだ。

9
11
4

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
9
11