2017 © Pedro PelĂĄez
 

library php-functional

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

image

widmogrod/php-functional

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  • Thursday, June 14, 2018
  • by widmogrod
  • Repository
  • 13 Watchers
  • 266 Stars
  • 147,573 Installations
  • PHP
  • 2 Dependents
  • 0 Suggesters
  • 11 Forks
  • 7 Open issues
  • 38 Versions
  • 9 % Grown

The README.md

PHP Functional

Build Status Test Coverage Maintainability, (*1)

Introduction

Functional programing is a fascinating concept. The purpose of this library is to explore Functors, Applicative Functors and Monads in OOP PHP, and provide examples of real world use case., (*2)

Monad types available in the project: * State Monad * IO Monad * Free Monad * Either Monad * Maybe Monad * Reader Monad * Writer Monad, (*3)

Exploring functional programing space I noticed that working with primitive values from PHP is very hard and complicates implementation of many functional structures. To simplify this experience, set of higher order primitives is introduced in library: * Num * Sum * Product * Stringg * Listt (a.k.a List Monad, since list is a protected keyword in PHP), (*4)

Applications

Known applications of this project - Algorithm W implemented in PHP based on Martin GrabmĂŒller work., (*5)

Installation

composer require widmogrod/php-functional

Development

This repository follows semantic versioning concept. If you want to contribute, just follow CONTRIBUTING.md, (*6)

Testing

Quality assurance is brought to you by: - PHPUnit - Eris - QuickCheck and property-based testing tools to the PHP and PHPUnit ecosystem. - PHP-CS-Fixer - A tool to automatically fix PHP coding standards issues, (*7)

composer test
composer fix 

Use Cases

You can find more use cases and examples in the example directory., (*8)

NOTE: Don't be confused when browsing thought examples you will see phrase like "list functor" and in this library you will see Widmogrod\Primitive\Listt. Monad is Functor and Applicative. You could say that Monad implements Functor and Applicative., (*9)

List Functor

use Widmogrod\Functional as f;
use Widmogrod\Primitive\Listt;

$list = f\fromIterable([
   ['id' => 1, 'name' => 'One'],
   ['id' => 2, 'name' => 'Two'],
   ['id' => 3, 'name' => 'Three'],
]);

$result = $list->map(function($a) {
    return $a['id'] + 1;
});

assert($result === f\fromIterable([2, 3, 4]));

List Applicative Functor

Apply function on list of values and as a result, receive list of all possible combinations of applying function from the left list to a value in the right one., (*10)

[(+3),(+4)] <*> [1, 2] == [4, 5, 5, 6]
use Widmogrod\Functional as f;
use Widmogrod\Primitive\Listt;

$listA = f\fromIterable([
    function($a) {
        return 3 + $a;
    },
    function($a) {
        return 4 + $a;
    },
]);
$listB = f\fromIterable([
    1, 2
]);

$result = $listA->ap($listB);

assert($result === f\fromIterable([4, 5, 5, 6]));

Maybe Monoid

Using Maybe as an instance of Monoid simplifies concat and reduce operations by using Maybe's abstraction over potentially missing values. See an example of constructing a person's full name from first, middle, and last without having to explicitly check if each part exists., (*11)

Maybe and List Monad

Extracting from a list of uneven values can be tricky and produce nasty code full of if (isset) statements. By combining List and Maybe Monad, this process becomes simpler and more readable., (*12)

use Widmogrod\Monad\Maybe;
use Widmogrod\Primitive\Listt;

$data = [
    ['id' => 1, 'meta' => ['images' => ['//first.jpg', '//second.jpg']]],
    ['id' => 2, 'meta' => ['images' => ['//third.jpg']]],
    ['id' => 3],
];

// $get :: String a -> Maybe [b] -> Maybe b
$get = function ($key) {
    return f\bind(function ($array) use ($key) {
        return isset($array[$key])
            ? Maybe\just($array[$key])
            : Maybe\nothing();
    });
};

$result = f\fromIterable($data)
    ->map(Maybe\maybeNull)
    ->bind($get('meta'))
    ->bind($get('images'))
    ->bind($get(0));

assert(f\valueOf($result) === ['//first.jpg', '//third.jpg', null]);

Either Monad

In php world, the most popular way of saying that something went wrong is to throw an exception. This results in nasty try catch blocks and many of if statements. Either Monad shows how we can fail gracefully without breaking the execution chain and making the code more readable. The following example demonstrates combining the contents of two files into one. If one of those files does not exist the operation fails gracefully., (*13)

use Widmogrod\Functional as f;
use Widmogrod\Monad\Either;

function read($file)
{
    return is_file($file)
        ? Either\Right::of(file_get_contents($file))
        : Either\Left::of(sprintf('File "%s" does not exists', $file));
}

$concat = f\liftM2(
    read(__DIR__ . '/e1.php'),
    read('aaa'),
    function ($first, $second) {
        return $first . $second;
    }
);

assert($concat instanceof Either\Left);
assert($concat->extract() === 'File "aaa" does not exists');

IO Monad

Example usage of IO Monad. Read input from stdin, and print it to stdout., (*14)

use Widmogrod\Monad\IO as IO;
use Widmogrod\Functional as f;

// $readFromInput :: Monad a -> IO ()
$readFromInput = f\mcompose(IO\putStrLn, IO\getLine, IO\putStrLn);
$readFromInput(Monad\Identity::of('Enter something and press <enter>'))->run();

Writer Monad

The Writer monad is useful to keep logs in a pure way. Coupled with filterM for example, this allows you to know exactly why an element was filtered., (*15)


use Widmogrod\Monad\Writer as W; use Widmogrod\Functional as f; use Widmogrod\Primitive\Stringg as S; $data = [1, 10, 15, 20, 25]; $filter = function($i) { if ($i % 2 == 1) { return W::of(false, S::of("Reject odd number $i.\n")); } else if($i > 15) { return W::of(false, S::of("Reject $i because it is bigger than 15\n")); } return W::of(true); }; list($result, $log) = f\filterM($filter, $data)->runWriter();

Reader Monad

The Reader monad provides a way to share a common environment, such as configuration information or class instances, across multiple functions., (*16)


use Widmogrod\Monad\Reader as R; use Widmogrod\Functional as f; function hello($name) { return "Hello $name!"; } function ask($content) { return R::of(function($name) use($content) { return $content. ($name == 'World' ? '' : ' How are you?'); }); } $r = R\reader('hello') ->bind('ask') ->map('strtoupper'); assert($r->runReader('World') === 'HELLO WORLD!') assert($r->runReader('World') === 'HELLO GILLES! HOW ARE YOU?')

Free Monad in PHP

Imagine that you first write business logic and don't care about implementation details like: - how and from where get user discounts - how and where save products in basket - and more ..., (*17)

When your business logic is complete, then you can concentrate on those details., (*18)

Free monad enables you to do exactly that, and more: - Write business logic first - Write your own DLS (domain specific language) - Decouple implementation from interpretation., (*19)

Echo program

Example Free Monad example of echo program can be found here: - See source code of FreeMonadTest.php - example based on second implementation of Free, based on Haskell implementation, (*20)

DSL for BDD tests

Example that use Free Monad to creates simple DSL (Domain Specific Language) to define BDD type of framework:, (*21)

$state = [
    'productsCount' => 0,
    'products' => [],
];

$scenario =
    Given('Product in cart', $state)
        ->When("I add product 'coca-cola'")
        ->When("I add product 'milk'")
        ->Then("The number of products is '2'");

$result = $scenario->Run([
    "/^I add product '(.*)'/" => function ($state, $productName) {
        $state['productsCount'] += 1;
        $state['products'][] = $productName;

        return $state;
    },
], [
    "/^The number of products is '(\d+)'/" => function ($state, int $expected) {
        return $state['productsCount'] === $expected;
    },
]);

Free Monad Calculator example

Example of a DSL for a naive calculator that is implemented by using FreeMonad., (*22)

Free monad can be interpreted as a real calculator or calculation formatter a.k.a. pretty printer. Additional thing that I wanted to tackle was a Free Monad Optimisation., (*23)

Considering that Free Monad is like AST, question arose in my mind - can I travers it and update it to simplify computation? Hot to do it? What are limitation of Free Monad? Calculator example is an outcome of those questions., (*24)

$calc = mul(
    sum(int(2), int(1)),
    sum(int(2), int(1))
);

$expected = '((2+1)^2)';

$result = foldFree(compose(interpretPrint, optimizeCalc), $calc, Identity::of);
$this->assertEquals(
    Identity::of(Stringg::of($expected)),
    $result
);

Haskell do notation in PHP

Why Haskell's do notation is interesting?, (*25)

In Haskell is just an "syntax sugar" and in many ways is not needed, but in PHP control flow of monads can be hard to track., (*26)

Consider example, that use only chaining bind() and compare it to the same version but with do notation in PHP., (*27)

Control flow without do notation

$result = Identity::of(1)
    ->bind(function ($a) {
        return Identity::of(3)
            ->bind(function ($b) use ($a) {
                return Identity::of($a + $b)
                    ->bind(function ($c) {
                        return Identity::of($c * $c);
                    });
            });
    });

$this->assertEquals(Identity::of(16), $result);

Control flow with do notation

$result = doo(
    let('a', Identity::of(1)),
    let('b', Identity::of(3)),
    let('c', in(['a', 'b'], function (int $a, int $b): Identity {
        return Identity::of($a + $b);
    })),
    in(['c'], function (int $c): Identity {
        return Identity::of($c * $c);
    })
);

assert($result === Identity::of(16));

Everyone needs to judge by itself, but in my opinion do notationimprove readability of code in PHP., (*28)

Book Functional PHP by Gilles Crettenand

In recently published book Functional PHP by Gilles Crettenand, you can learn more applications of widmogrod/php-functional, see how it compares to other projects and how in an effortless way apply functional thinking in daily work., (*29)

Buy the book at PacktPub, (*30)

References

Here links to their articles/libraries that help me understood the domain: * http://drboolean.gitbooks.io/mostly-adequate-guide * https://github.com/fantasyland/fantasy-land * http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html * http://learnyouahaskell.com/functors-applicative-functors-and-monoids * http://learnyouahaskell.com/starting-out#im-a-list-comprehension * http://robotlolita.me/2013/12/08/a-monad-in-practicality-first-class-failures.html * http://robotlolita.me/2014/03/20/a-monad-in-practicality-controlling-time.html * https://github.com/folktale/data.either * https://github.com/widmogrod/php-algorithm-w, (*31)

The Versions

14/06 2018

dev-master

9999999-dev

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

14/06 2018

5.1.0

5.1.0.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

01/06 2018

dev-feature/algorithm-w

dev-feature/algorithm-w

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

24/02 2018

dev-feature/refactor

dev-feature/refactor

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

18/02 2018

dev-feature/code-generate

dev-feature/code-generate

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

18/02 2018

5.0.0

5.0.0.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

30/01 2018

dev-feature/calculator-free

dev-feature/calculator-free

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires

02/01 2018

4.2.0

4.2.0.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires

31/12 2017

dev-feature/lazy-solution

dev-feature/lazy-solution

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires

30/12 2017

4.1.0

4.1.0.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires

30/12 2017

dev-feature/make-list-more-lazy

dev-feature/make-list-more-lazy

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires

29/12 2017

4.0.1

4.0.1.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires

21/12 2017

4.0.0

4.0.0.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires

17/12 2017

3.4.0

3.4.0.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires

13/12 2017

3.3.0

3.3.0.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

  • php >=7.1

 

The Development Requires

12/12 2017

3.2.0

3.2.0.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Development Requires

11/12 2017

2.0.0-beta3

2.0.0.0-beta3

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Development Requires

11/12 2017

3.1.0

3.1.0.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Development Requires

14/06 2017

dev-feature/free-monad

dev-feature/free-monad

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Development Requires

20/10 2016

dev-krtek4-filterM

dev-krtek4-filterM

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Development Requires

16/10 2016

3.0.0

3.0.0.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Development Requires

07/10 2016

2.1.1

2.1.1.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Development Requires

22/11 2015

2.1.0

2.1.0.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Development Requires

22/11 2015

2.0.1

2.0.1.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Development Requires

10/11 2015

2.0.0

2.0.0.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Development Requires

29/10 2015

2.0.0-beta2

2.0.0.0-beta2

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Development Requires

04/10 2015

2.0.0-beta1

2.0.0.0-beta1

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

16/08 2015

1.4.0

1.4.0.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

03/08 2015

1.3.0

1.3.0.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

02/08 2015

1.2.1

1.2.1.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

02/08 2015

1.2.0

1.2.0.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

07/07 2015

1.1.0

1.1.0.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

02/05 2015

1.0.1

1.0.1.0

Functors, Applicative and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

19/03 2015

1.0.0

1.0.0.0

Functors, Applicators and Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

01/03 2015

0.3.0

0.3.0.0

Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

01/03 2015

0.2.1

0.2.1.0

Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

28/02 2015

0.2.0

0.2.0.0

Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Requires

 

The Development Requires

24/02 2015

0.1.0

0.1.0.0

Monads are fascinating concept. Purpose of this library is to explore them in OOP PHP world.

  Sources   Download

MIT

The Development Requires