fn icon indicating copy to clipboard operation
fn copied to clipboard

Proposal: applyTo() utility function

Open tobia opened this issue 4 years ago • 2 comments

Hello and thank you for writing this library.

Whenever I'm defining a pipeline of functions to be applied immediately to a starting value, instead of being given a name and saved for later, I use the following utility function:

/**
 * Accept an input and some callables, then apply the callables in order.
 *
 * @param   $input      Input to the computation.
 * @param   $callables  Any number of callables to be composed using pipe().
 * @return              Final result of the computation.
 */
function applyTo($input, callable ...$callables) {
    return f\pipe(...$callables)($input);
}

This enables a Bash-like, left-to-right / top-to-bottom style of pipeline definition and application, for those (like me) who find it more readable than the backwards style of compose():

$res = applyTo([1,2,3,4],            // <- input
    c\filter(fn ($x) => $x > 2),   // <- first step
    c\map(fn ($x) => $x * 3),      // ...
    c\toArray,                     // <- last step
);

assert($res == [9, 12]);

Here is a more complex example, showing how to use one applyTo() inside another:

$pages = [
    (object)['slug'=>'about', 'name'=>'About Us'],
    (object)['slug'=>'about', 'name'=>'About You'],
    (object)['slug'=>'news',  'name'=>'Latest News'],
];

$duplicate = applyTo($pages,
    c\groupBy(fn ($page) => $page->slug),
    c\filter(fn ($group) => count($group) > 1),
    c\map(fn ($pages) =>
        "Pages with slug '{$pages[0]->slug}': " . applyTo($pages,
            c\map(fn ($page) => "({$page->name})"),
            c\join(", "),
        )
    ),
    c\join(". "),
);

assert($duplicate == "Pages with slug 'about': (About Us), (About You)");

Do you have any suggestions / critiques? Would you accept a pull request for this function?

I also thought about other calling styles, such as curried: applyTo($input)($fn1, $fn2...) or array: applyTo($input, [$fn1, $fn2...]) but ultimately I decided to keep things simple.

tobia avatar Mar 20 '21 19:03 tobia

Thanks for the suggestion @tobia, can you find examples of this type of function signature and naming in other functional libraries in php or in other languages?

not necessarily against it, but if there’s a similar concept in other communities that maybe use a different name or something, I’d like to keep consistent if possible.

ragboyjr avatar Mar 20 '21 20:03 ragboyjr

Right. I came up with the name and signature myself, because that's what I needed. I'll look into other languages, because the state of PHP functional libraries is quite abysmal. (This is the only libraries that has curried versions of the functions, for example.)

tobia avatar Mar 20 '21 20:03 tobia