расширенное функциональное программирование php - создание метода карри, аналогичного ramdaJS
Требования:
- подставка для держателя места
- частично применяемые функции могут быть применены к частично применяемым функциям
- каррирование
- 5.6 Поддержка PHP
Вот моя попытка, однако она поддерживает только hhvm 3.7, как вы можете видеть в примере на http://3v4l.org/0i5FV
<?php
class Placeholder{}
function curry(callable $func, ... $curriedArgs) {
return function(...$fulfillment) use ($func, $curriedArgs) {
$removedPlaceheldArgs = array_map(function($arg) use ($fulfillment) {
if ($arg instanceof Placeholder)
return array_shift($fulfillment);
return $arg;
}, $curriedArgs);
return $func(...array_merge($removedPlaceheldArgs, $fulfillment));
};
};
Вот пример моего использования:
$resultset = json_decode('[{
"id": 1,
"gender": "Male",
"name": "Matthew"
}, {
"id": 2,
"gender": "Male",
"name": "Willie"
}, {
"id": 3,
"gender": "Female",
"name": "Ann"
}, {
"id": 4,
"gender": "Female",
"name": "Margaret"
}, {
"id": 5,
"gender": "Female",
"name": "Marie"
}]',TRUE);
$filterGender = function($row,$gender){
return $row['gender']==$gender;
};
$detectMen = curry($filterGender,(new Placeholder),'Male');
$detectWomen = curry($filterGender,(new Placeholder),'Female');
var_dump($detectMen(['gender'=>'Male'])); //works -- expected result TRUE
$getLadies = curry('array_filter',(new Placeholder),$detectWomen);
var_dump($getLadies($resultset)); //does not work -- expected result Ladies from result set
Может ли результат $getladies быть достигнут в PHP 5.6 вместо простого hhvm?
2
2 answers
Это не очень красиво, но это должно быть близкой эмуляцией текущей функции Ramda curry
.
namespace Phamda {
function _() {
static $placeholder;
if ($placeholder === null) {
$placeholder = new \stdClass;
}
return $placeholder;
}
function curryN($n, $f) {
$curryNRec = function($recv) use ($n, $f, &$curryNRec) {
return function () use ($recv, $n, $f, &$curryNRec) {
$left = $n;
$argsIdx = 0;
$combined = array();
$combindedIdx = 0;
$args = func_get_args();
while ($combindedIdx < count($recv) || $argsIdx < count($args)) {
if ($combindedIdx < count($recv)
&& ($recv[$combindedIdx] !== _() || $argsIdx > count($args))) {
$result = $recv[$combindedIdx];
} else {
$result = $args[$argsIdx];
$argsIdx += 1;
}
$combined[$combindedIdx] = $result;
$combindedIdx += 1;
if ($result !== _()) {
$left -= 1;
}
}
if ($left <= 0) {
return call_user_func_array($f, $combined);
} else {
return $curryNRec($combined);
}
};
};
return $curryNRec([]);
}
function curry($f) {
$fRefl = new \ReflectionFunction($f);
return curryN($fRefl->getNumberOfParameters(), $f);
}
}
И используя ваш пример:
use Phamda as P;
$resultset = json_decode('[{
"id": 1,
"gender": "Male",
"name": "Matthew"
}, {
"id": 2,
"gender": "Male",
"name": "Willie"
}, {
"id": 3,
"gender": "Female",
"name": "Ann"
}, {
"id": 4,
"gender": "Female",
"name": "Margaret"
}, {
"id": 5,
"gender": "Female",
"name": "Marie"
}]', true);
$filterGender = P\curry(function($row, $gender){
return $row['gender'] == $gender;
});
$detectMen = $filterGender(P\_(), 'Male');
$detectWomen = $filterGender(P\_(), 'Female');
var_dump($detectMen(['gender' => 'Male']));
// bool(true)
$filter = P\curry('array_filter');
$getLadies = $filter(P\_(), $detectWomen);
var_dump($getLadies($resultset));
/*
array(3) {
[2] =>
array(3) {
'id' =>
int(3)
'gender' =>
string(6) "Female"
'name' =>
string(3) "Ann"
}
[3] =>
array(3) {
'id' =>
int(4)
'gender' =>
string(6) "Female"
'name' =>
string(8) "Margaret"
}
[4] =>
array(3) {
'id' =>
int(5)
'gender' =>
string(6) "Female"
'name' =>
string(5) "Marie"
}
}
*/
1
Author: Scott Christopher, 2015-07-16 02:00:32
Вы можете использовать частичное применение и функции карри из Нестандартной библиотеки PHP:
use function nspl\f\rpartial;
$detectMen = rpartial($filterGender, 'Male');
$detectWomen = rpartial($filterGender, 'Female');
var_dump($detectMen(array('gender' => 'Male')));
$getLadies = rpartial('array_filter', $detectWomen);
var_dump($getLadies($resultset));
0
Author: Ihor Burlachenko, 2015-12-20 23:01:34