2

Requirements:

  1. place holder support
  2. partial applied functions can be applied to partially applied functions
  3. currying
  4. 5.6 PHP support

here is my attempt however it only supports hhvm 3.7 as you can see in the example on 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));
    };
};

here is an example of my usage:

$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

can the $getLadies result be achieved in PHP 5.6 instead of just hhvm?

arcanine
  • 1,933
  • 1
  • 15
  • 22

2 Answers2

1

It's not pretty, but this should be a close emulation of Ramda's current curry function.

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);
    }
}

And using your example:

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"
  }
}
*/
Scott Christopher
  • 6,458
  • 23
  • 26
0

You can use partial application and curry functions from Non-standard PHP library:

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));
Ihor Burlachenko
  • 4,689
  • 1
  • 26
  • 25