Skip to content

Instantly share code, notes, and snippets.

@mudge
Last active August 29, 2015 13:56
Show Gist options
  • Save mudge/8832334 to your computer and use it in GitHub Desktop.
Save mudge/8832334 to your computer and use it in GitHub Desktop.
A functional conundrum (that isn't PHP specific).
<?php
/* Given an anonymous function with a previously unspecified number of arguments like so: */
$f = function ($x, $y, $z) {
/* Do something interesting with $x, $y and $z. */
return;
};
/* How can I convert it into the following nested function (each function yielding one argument),
* finally calling $f when there are enough arguments?
*/
foo(function ($x) {
return foo(function ($y) use ($x) {
return foo(function ($z) use ($x, $y) {
return $f($x, $y, $z);
});
});
});
@mudge
Copy link
Author

mudge commented Feb 5, 2014

Thanks, @mattmacleod: you're right, it is bit of the old schönfinkeling.

My final implementation was taken from underscore-contrib's implementation of curry as I need to call my own function at each level to yield a new argument, only executing the original function at the end: https://github.com/mudge/php-microkanren/blob/master/src/MicroKanren/Mini.php#L58-L94

Reproduced here for posterity:

<?php
function fresh($f)
{
    $reflection = new \ReflectionFunction($f);
    $argCount = $reflection->getNumberOfParameters();

    if ($argCount === 0) {
        return $f();
    } else {
        return callFresh(function ($x) use ($f, $argCount) {
            return collectArgs($f, $argCount, array(), $x);
        });
    }
}

function collectArgs($f, $argCount, $args, $arg)
{
    $args[] = $arg;

    if (count($args) === $argCount) {
        return call_user_func_array($f, $args);
    } else {
        return callFresh(function ($x) use ($f, $argCount, $args) {
            return collectArgs($f, $argCount, $args, $x);
        });
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment