Coder Social home page Coder Social logo

phamda's Introduction

Phamda

Phamda is an auto-curried function library for PHP, heavily inspired by the Javascript library Ramda. PHP 7.0+ or HHVM is required.

Installation

Using composer: composer require phamda/phamda

Documentation

Documentation is available on Read the Docs.

Examples

These examples highlight the major features of Phamda. Basic usage examples can also be found on the function list.

Currying

Nearly all of the functions use automatic partial application or currying. For example you can call the filter function with only the predicate callback and get a new function:

use Phamda\Phamda as P;

$isPositive   = function ($x) { return $x > 0; };
$list         = [5, 7, -3, 19, 0, 2];
$getPositives = P::filter($isPositive);

$getPositives($list) === [5, 7, 3 => 19, 5 => 2];

The final result is the same as using two arguments directly. Of course this new function could now be used to filter other lists as well.

It's also possible to create new curried functions, including from native PHP functions. The curry function takes a function and initial parameters and returns a new function:

$replaceBad = P::curry('str_replace', 'bad', 'good');

$replaceBad('bad day') === 'good day';
$replaceBad('not bad') === 'not good';

Composition

Phamda functions are composable. The basic functions can be used to create new, more complex functions. There are also several functions to help with function composition. For example the compose function takes multiple argument functions and returns a new function. Calling this new function applies the argument functions in succession:

$double           = function ($x) { return $x * 2; };
$addFive          = function ($x) { return $x + 5; };
$addFiveAndDouble = P::compose($double, $addFive);

$addFiveAndDouble(16) === 42;

// Equivalent to calling $double($addFive(16));

Often the pipe function is a more natural way to compose functions. It is similar to compose, but the argument functions are applied in reverse order:

$doubleAndAddFive = P::pipe($double, $addFive);

$doubleAndAddFive(16) === 37;

Parameter order

When using functional techniques it's usually most convenient if data is the last parameter. Often native PHP and library functions do not follow for this pattern. Phamda includes some tools to make it easier to use these functions functionally. The simplest is flip, it switches the order of the first two parameters:

$pow   = function ($a, $b) { return $a ** $b; };
$powOf = P::flip($pow);

$pow(2, 8) === 256;
$powOf(2, 8) === 64;

twist is somewhat more complicated and will return a new function where the original first parameter is now last:

$redact = P::twist('substr_replace')('REDACTED', 5);

$redact('foobarbaz') === 'foobaREDACTED';

Using twist may not work well with variadic functions. This is where twistN can be useful. It requires an additional parameter to set the location of the replaced parameter.

All of these functions return curried functions.

Pipelines

Combining these techniques allows the building of function pipelines. In this example they are applied to processing a list of badly formatted product data:

$products = [
    ['category' => 'QDT', 'weight' => 65.8, 'price' => 293.5, 'number' => 15708],
    ['number' => 59391, 'price' => 366.64, 'category' => 'NVG', 'weight' => 15.5],
    ['category' => 'AWK', 'number' => 89634, 'price' => 341.92, 'weight' => 35],
    ['price' => 271.8, 'weight' => 5.3, 'number' => 38718, 'category' => 'ETW'],
    ['price' => 523.63, 'weight' => 67.9, 'number' => 75905, 'category' => 'YVM'],
    ['price' => 650.31, 'weight' => 3.9, 'category' => 'XPA', 'number' => 46289],
    ['category' => 'WGX', 'weight' => 75.5, 'number' => 26213, 'price' => 471.44],
    ['category' => 'KCF', 'price' => 581.85, 'weight' => 31.9, 'number' => 48160],
];

$formatPrice = P::flip('number_format')(2);
$process     = P::pipe(
    P::filter( // Only include products that...
        P::pipe(
            P::prop('weight'), // ... weigh...
            P::gt(50.0) // ... less than 50.0.
        )
    ),
    P::map( // For each product...
        P::pipe(
            // ... drop the weight field and fix field order:
            P::pick(['number', 'category', 'price']),
            // ... and format the price:
            P::evolve(['price' => $formatPrice])
        )
    ),
    P::sortBy( // Sort the products by...
        P::prop('number') // ... comparing product numbers.
    )
);

$process($products) === [
    ['number' => 38718, 'category' => 'ETW', 'price' => '271.80'],
    ['number' => 46289, 'category' => 'XPA', 'price' => '650.31'],
    ['number' => 48160, 'category' => 'KCF', 'price' => '581.85'],
    ['number' => 59391, 'category' => 'NVG', 'price' => '366.64'],
    ['number' => 89634, 'category' => 'AWK', 'price' => '341.92'],
];

License

MIT license, see LICENSE file.

phamda's People

Contributors

mpajunen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

juho-probis

phamda's Issues

P::explode not accepting empty string delimiter

A big oops.... It's in javascript that strings can be split with an empty delimiter, not in PHP. Disregard this issue!!

Just wondering what's the point of refusing an empty string as a delimiter for P::explode. The std PHP explode function simply returns an array of all characters when called with an empty delimiter, which is convenient.

problem with PHP 8

Many functions use the php function "method_exists" to check if a given method is defined in an object being operated on. For example, P::map($val, $fn) checks if $val has the method 'map' defined as a first step in order to use the object's method if it does exist. With versions of PHP < 8, method_exists($array, 'method') returns false. With PHP 8, it crashes as method_exists accepts only objects or classes.

As a result, Phamda is no longer usable.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.