rfc:currying

This is an old revision of the document!


Request for Comments: Currying

  • Version: 0.9
  • Date: 2011-06-11
  • Author: Lars Strojny lstrojny@php.net
  • Status: Draft

Introduction

Currying is a way to transform a function taking multiple arguments into nested functions so that the outmost function takes a single argument.

Currying, Schmurrying?

Think about passing a callback to a function. Let's find out if a list of characters are part of “foo”:

$chars = array("o", "f", "b");
array_map($chars, function($char) {
    return strpos('foo', $char);
});

A shorter form (with currying) would be:

$chars = array("o", "f", "b");
array_map($chars, curry_left('strpos', 'foo'));

The imaginative function curry_left() here returns an anonymous function which takes a single parameter:

<?php
function curry_left($callable)
{
    $outerArguments = func_get_args();
    array_shift($outerArguments);
 
    return function() use ($callable, $outerArguments) {
        return call_user_func_array($callable, array_merge($outerArguments, func_get_args()));
    };
}
 
function curry_right($callable)
{
    $outerArguments = func_get_args();
    array_shift($outerArguments);
 
    return function() use ($callable, $outerArguments) {
        return call_user_func_array($callable, array_merge(func_get_args(), $outerArguments));
    };
}

Let's demonstrate the use of curry_right() on a slightly different example: find out if character “f” is in a list of word:

$words = array('foo', 'bar', 'baz');
array_map($words, curry_right('strpos', 'a'));

Proposal

PHP has a long standing tradition of not providing a purists implementation of a certain feature. This is why I propose currying as a syntax enhancement in a way I feel even people new to functional'ish programming can understand what's going on.

The words example from aboe with currying as a syntax:

$words = array('foo', 'bar', 'baz');
array_map($words, curry strpos(..., 'a'));

The char example:

$chars = array("o", "f", "b");
array_map($chars, curry strpos(..., 'foo'));

We may spot, that two new tokens are introduced, T_CURRY and T_FILL (“...”). The approach here is to make currying as explicit as possible (syntax wise) and not fall on the purists edge. For example we allow curry to return functions with two parameters. Example:

$func = curry str_replace(..., ..., "foobar");
$func('foo', 'bar'); // barbar
$func('foo', 'baz'); // bazbar

Curried functions can be curried again:

$func = curry str_replace(..., ..., "foobar");
$func = curry $func(..., "baz");
$func("foo"); // bazbar
$func("bar"); // foobaz

Notes

  • Keyword curry should have an alias schoenfinkel
  • I could use some helping hand with the parser work, if you are interested, drop me a message

References

Changelog

  • Initial draft
rfc/currying.1307315426.txt.gz · Last modified: 2017/09/22 13:28 (external edit)