Giter Site home page Giter Site logo

ace411 / bingo-functional Goto Github PK

View Code? Open in Web Editor NEW
64.0 11.0 8.0 2.3 MB

A simple functional programming library for PHP

Home Page: https://bingo-functional-docs.now.sh/

License: Apache License 2.0

PHP 100.00%
php php7 php-library functional-programming functional-php functional bingo-framework either-monad maybe-monad functors

bingo-functional's People

Contributors

ace411 avatar codacy-badger avatar desure85 avatar gitter-badger avatar peter279k avatar stylecibot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  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  avatar  avatar  avatar  avatar

bingo-functional's Issues

Property tests

Property tests are a great way to ensure function completeness - they help validate the invariants in a function's intended behavior. I currently feel that the unit tests written for this library, though accurate, are not complete. I currently envisage an adoption of property testing ideas for the library. For example:

public function testIdentityFunctionConveysInputAsOutput()
{
  $this->forAll(
    Generator\int(),
    Generator\string(),
    Generator\float(),
    Generator\bool()
  )
    ->then(function ($value) {
      $id = A\identity($value);
      
      $this->assertEquals($value, $id);
      $this->assertTrue(gettype($value) == gettype($id));
    });
}

The snippet above utilizes the Eris package to perform property tests. The result is a litany of assertions which ordinarily - constitute atomic use cases.

Improve the Pattern Matching Algorithm

Implemented in v1.9.0 along with a variety of helper functions was the patternMatch() function. It has undergone several modifications since its inception and still feels a bit incomplete. Why - one might ask? The snippet below evaluates to a wildcard pattern when it should not.

use function \Chemem\Bingo\Functional\PatternMatching\patternMatch;

$match = patternMatch(
  [
    '[_, "foo"]' => function () { return 'first-pattern'; },
    '_' => function () { return 'wildcard'; }
  ],
  explode('/', 'api/foo')
);

The snippet above is a syntactical facsimile of the Haskell code shown below which evaluates to the string, first-pattern.

patternMatch :: [a] -> a
patternMatch (_,  foo) = "first-pattern"
patternMatch _ = "wildcard"

I intend to fix the problem that is the current patternMatch function's inability to reconcile list patterns that contain wildcards in them.

Integrate the coding style tool/service

As we see, the package doesn't follow the PSR-2 coding style.
To fix this coding style issue automatically, I suggest we can use the PHP-CS-Fixer or StyleCI to complete this issue.

Replace the self-defined functions with the PHP native functions

As title. According to the Unique function, it looks like we use the foreach loop to try to get the unique array on specific array collection.

But the PHP has the native array_unique function to help us to get the unique array quickly without using the foreach loop.

I think we can use the native PHP functions easily and it will be better than using foreach loop.

Fatal error when using Nothing::flatMap

Consider the following code:

$maybe = Maybe::fromValue(null)
    ->flatMap(function () {
        return Maybe::fromValue('some value');
    })
    ->getOrElse('default');

It causes the error: PHP Fatal error: Uncaught Error: Call to a member function getOrElse() on null. Probably Nothing::flatMap should return an instance of Nothing instead of null.

Anomalous `assocPath` function behavior

The purpose of the assocPath() function is to create a shallow clone of a list with an overwritten value assigned to the index at the end of a (specified) traversable path. The current behavior is such that a call to the said function appends - to a target list - a discretionary value whose index is the first item in the specified path - in the event that the said path does not exist. Consider the example to follow.

use function Chemem\Bingo\Functional\assocPath;

$list = assocPath(['foo', 'bar'], 2, ['bar' => 2]);

var_dump($list);

The output of the snippet above - per the current constitution of the assocPath() function signature - is as follows.

array(2) {
  ["bar"]=>
  int(2)
  ["foo"]=>
  int(2)
}

The result depicted above is erroneous and invalidates the assocPath() function. The correct result is a clone of the original array - that contains a new entry: a hashtable with a single dimension that corresponds to the path 'foo' -> 'bar'. The aberrant behavior depicted in the previous snippet - upon correction - should produce output similar to that in the snippet below.

array(2) {
  ["bar"]=>
  int(2)
  ["foo"]=>
  array(1) {
    ["bar"]=>
    int(2)
  }
}

Migrating to GitHub Action

Since the Travis CI building has been very slow, I think it's time to migrate the Travis CI to GitHub Actions.

Manual autoloader

In installation section, I think the manual awesome package installation without Composer is not the proper way.
It should create the autoloader.php in project root folder so that it can be friendly with the package users ๐Ÿ‘ . And I also prefer the psr-4 autoloader.

What do you think?

Anomalous `assocPath` function behavior

The purpose of the assocPath() function is to create a shallow clone of a list with an overwritten value assigned to the index at the end of a (specified) traversable path. The current behavior is such that a call to the said function appends - to a target list - a discretionary value whose index is the first item in the specified path - in the event that the said path does not exist. Consider the example to follow.

use function Chemem\Bingo\Functional\assocPath;

$list = assocPath(['foo', 'bar'], 2, ['bar' => 2]);

var_dump($list);

The output of the snippet above - per the current constitution of the assocPath() function signature - is as follows.

array(2) {
  ["bar"]=>
  int(2)
  ["foo"]=>
  int(2)
}

The result depicted above is erroneous and invalidates the assocPath() function. The correct result is a clone of the original array - that contains a new entry: a hashtable with a single dimension that corresponds to the path 'foo' -> 'bar'. The aberrant behavior depicted in the previous snippet - upon correction - should produce output similar to that in the snippet below.

array(2) {
  ["bar"]=>
  int(2)
  ["foo"]=>
  array(1) {
    ["bar"]=>
    int(2)
  }
}

Shouldn't IO::bind be lazy?

Consider the following code:

use Chemem\Bingo\Functional\Functors\Monads\IO;

$io = IO::of(function () {
    echo 'LOG 1', PHP_EOL;
})
->bind(function () {
    return IO::of(function () {
        echo 'LOG 2', PHP_EOL;
    });
});

It prints LOG 1 even $io->exec() is not called.

Anomalous `assocPath` function behavior

The purpose of the assocPath() function is to create a shallow clone of a list with an overwritten value assigned to the index at the end of a (specified) traversable path. The current behavior is such that a call to the said function appends - to a target list - a discretionary value whose index is the first item in the specified path - in the event that the said path does not exist. Consider the example to follow.

use function Chemem\Bingo\Functional\assocPath;

$list = assocPath(['foo', 'bar'], 2, ['bar' => 2]);

var_dump($list);

The output of the snippet above - per the current constitution of the assocPath() function signature - is as follows.

array(2) {
  ["bar"]=>
  int(2)
  ["foo"]=>
  int(2)
}

The result depicted above is erroneous and invalidates the assocPath() function. The correct result is a clone of the original array - that contains a new entry: a hashtable with a single dimension that corresponds to the path 'foo' -> 'bar'. The aberrant behavior depicted in the previous snippet - upon correction - should produce output similar to that in the snippet below.

array(2) {
  ["bar"]=>
  int(2)
  ["foo"]=>
  array(1) {
    ["bar"]=>
    int(2)
  }
}

Compact function purges TRUE from an array.

The description of the Compact function says that it purges an array of falsey values (null, false). It means that true should stay in the array, right? Though, that test will fail:

$mixed = [1, 2, 'foo', false, null, true];
$purged = A\compact($mixed);
$this->assertEquals([1, 2, 'foo', true], $purged);

It seems that either the function description is incorrect or the function does not function properly.

getJust method in Nothing class is strange

Consider the following code snippet:

public function getJust()
{
}

It looks strange because this method does nothing after using that.

I think it should return null because it's the Nothing class ๐Ÿ‘.

getOrElse method in Nothing class is strange

Consider the following code snippet:

public function getOrElse($default)
{
        return $this;
}

I don't know the type of $default and pass the correct variable to this method.

And the getter method should not require any argument I think.

Maybe this method should be changed into:

public function getOrElse(Maybe $maybe)
{
        return $this->orElse(Maybe $maybe);
}

@ace411 , what do you think?

PHP 8+ compatibility

The dependency functional-php/pattern-matching (which looks unmaintained) is using match, which is a reserved word in PHP 8.0 since it now has a built-in pattern matching. That breaks library's compatibility with newer PHP versions, which should be warned in readme while the problem is being addressed.

Recursion vs Loop structures

I have implemented recursive functions in the structures of multiple helper functions map, filter, and fold inclusive. I recently ran some tests to ascertain the potency of said implementations and the results - higher memory usage for large data sets even with trampoline optimization - triggered a contemplation of the perks of PHP loops. I ran some more tests centered around the usage of foreach loops and discovered a performance increment for large datasets.

My current dilemma is this: I am not willing to revert to PHP loops but want to find a way to justify the recursion implemented in the library.

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.