{"id":15029840,"url":"https://github.com/timfennis/apply","last_synced_at":"2026-03-07T05:07:05.326Z","repository":{"id":34934092,"uuid":"183219448","full_name":"timfennis/apply","owner":"timfennis","description":"Functional Programming in PHP","archived":false,"fork":false,"pushed_at":"2023-04-19T18:26:27.000Z","size":1426,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-07-18T06:57:58.456Z","etag":null,"topics":["arrow","functional-programming","monad","php","php-library","php74"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/timfennis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-04-24T11:57:19.000Z","updated_at":"2022-01-20T17:51:28.000Z","dependencies_parsed_at":"2024-09-24T20:11:57.674Z","dependency_job_id":null,"html_url":"https://github.com/timfennis/apply","commit_stats":{"total_commits":86,"total_committers":3,"mean_commits":"28.666666666666668","dds":"0.32558139534883723","last_synced_commit":"7ee0bb2552aee3dab674363312b7fd6be3b05d2f"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/timfennis/apply","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timfennis%2Fapply","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timfennis%2Fapply/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timfennis%2Fapply/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timfennis%2Fapply/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/timfennis","download_url":"https://codeload.github.com/timfennis/apply/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timfennis%2Fapply/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30208730,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T03:24:23.086Z","status":"ssl_error","status_checked_at":"2026-03-07T03:23:11.444Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arrow","functional-programming","monad","php","php-library","php74"],"created_at":"2024-09-24T20:11:47.206Z","updated_at":"2026-03-07T05:07:05.302Z","avatar_url":"https://github.com/timfennis.png","language":"PHP","readme":"# Apply \n\n\n[![codecov](https://codecov.io/gh/timfennis/apply/branch/master/graph/badge.svg)](https://codecov.io/gh/timfennis/apply)\n[![Build Status](https://drone.timfennis.com/api/badges/timfennis/apply/status.svg)](https://drone.timfennis.com/timfennis/apply)\n\nApply is a **PHP Library** that aims to promote and bring functional programming ideas from different languages and \nlibraries such as Haskell, Scala, Kotlin, Arrow and Cats to PHP.\n\n## Stability\n\nThe library is currently very much a work in progress. Everything could change at any moment.\n\n## Contributing\n\nI'm currently looking for ideas, suggestions, criticisms and contributions. The library is very much in a draft state,\nsome functions probably don't work they way they 'should' and test coverage is still only 50ish percent.\n\n* If you have any ideas for functional programming concepts that could work well in PHP, please open an issue or PR and \nget involved.\n* If you see any functions that don't work the way they should, or could be improved performance wise feel free to open\na PR or issue and let me now!\n* If you have any ideas, long term visions, or do you just think this whole library is stupid? Feel free to open an \nissue and let me know! \n\n## Curried Functions\n \n### Collections\n\nAll collection functions in this library attempt to follow a pattern in terms of naming and argument order.\nUsually the names and arguments you'll find are taken from Haskell's standard library. Every function has a Curried\nversion where the argument order matches the one in Haskell. In this argument order the subject of the function is\nalways the last argument so that the curried functions can be used to create partially applied functions that can\nbe chained together in different ways. All of these functions also have imperative counterparts that are easier\nto use and read in some situations. These functions have the same argument order except that the subject is now\nthe first argument followed by the other arguments in the same order. This order is chosen because it's easier\nto read in imperative code and because it's similar to most other languages.\n\nFunctions that return collections of elements will always return Generators in order to be as lazy as possible.\nFunctions that return a single element, or a scalar value are not lazy. \n\n#### All\n\n```php\n$list = [5, 6, 7, 8, 9, 10];\n\n$gt4 = fn($n) =\u003e $n \u003e 4;\n$gt5 = fn($n) =\u003e $n \u003e 5;\n\nall($gt4)($list); // true because all items are greater than 4\nall($gt5)($list); // false because not all items are greater than 5\n```\n\n#### Any\n\nReturns true if any (or some) of the predicates are true.\n\n```php\n$list = [5, 6, 7, 8, 9, 10];\n\n$gt7 = fn($n) =\u003e $n \u003e 7;\n$gt20 = fn($n) =\u003e $n \u003e 20;\n\nany($gt7)($list); // true because all items are greater than 7\nany($gt20)($list); // false because none of the items are greater than 20\n```\n\n\n### `identity` and `constant`\n\nThese two guys can often be very useful in many situations. `constant` returns a function that always returns the value\nthat you passed to it. While identity is a function that always returns it's argument.\n\n```php\n$numbers = [1,2,3];\nmap(Functions::identity)($numbers); // [1,2,3]\nmap(constant(4))($numbers); // [4,4,4]\n```\n\n## Monads\n\nCheck [this](https://arrow-kt.io/docs/patterns/monads/) page for a good tutorial on what Monads are. You don't really \nhave to understand them in order to (ab)use them though.\n\n### Try\n\n`Attempt` represents the result of a computation that can either have a result when the computation was successful, or\nan exception if something went wrong. If the computation went correctly you get a `Success\u003cA\u003e` containing the result and \nif the computation goes wrong you get a `Failure` containing the exception.\n\n`Attempt` looks a lot like `Either` but is especially useful in situations where you have to consume some library or \nlanguage feature that throws unwanted exception. `Attempt` can be used to capture exceptions and performing computations\non the result without having to build complicated and verbose `try-catch` blocks. \n\n```php\nfunction loadFromAPI() {\n    throw new InvalidAuthenticationCredentialsException('Your authentication credentials are invalid');\n}\n\n$tryLoad = Attempt::of(fn() =\u003e loadFromAPI());\n$result = $tryLoad-\u003egetOrDefault(null); // returns null\n\nif ($tryLoad-\u003eisFailure()) {\n    // true it went wrong!\n}\n```\n\nMost often you may want to fold over the computation\n\n```php\n$tryLoad = Attempt::of(fn() =\u003e rollTheDice());\n\n$number = $tryLoad-\u003efold(\n    fn(Throwable $t) =\u003e 0,\n    fn(int $successValue) =\u003e $successValue + 1\n);\n```\n\n### Option (Maybe)\n\nThe Option monad is a modern rewrite of `schmittjoh/php-option` which can be found \n[here](https://github.com/schmittjoh/php-option). It's designed to be mostly compatible with its interface.\n\nSuggestions are welcome.\n\n### Either\n\n\n```php\n\n/**\n * @return Either\u003cstring, Response\u003e\n */\nfunction loadFromApi(): Either {\n    try { \n        return new Right(httpGet(\"http://example.com\"));\n    } catch (RequestException $e) {\n        return new Left(\"Request Error\");\n    } catch (ResponseException $e) {\n        return new Left(\"Response Error\");\n    }\n}\n\n```\n\nInstead of using `string` as type directly you probably want to define your own error types like `RequestError` and \n`ResponseError`. Those types could then have meaningful properties that assist with error handling.  \n\n### EvalM\n\nWrapper around a lazy computation.\n\n## Monad Comprehensions\n\nMany programming languages have a form of monad comprehensions, but they go by different names with slightly different\nimplementations. In Haskell, you have the 'do notation', in Scala you have for-comprehensions and in JavaScript you can \nuse async/await to accomplish similar results.\n\nIn PHP, we don't have much use for asynchronous programming and IO monads, but the syntax of monad comprehensions can\nstill offer us a way to combine the results of many monads elegantly.\n\nFirst let's look at one example that doesn't look very nice. Here we have two computations that can fail in some way.\nIn order to combine the results of these computations whe have to take them out of the 'package' that they came in, \ncombine the results and wrap them back up. Your code may look something like this.\n\n```php\n$computeA = fn() =\u003e Option::fromValue(1);\n$computeB = fn() =\u003e Option::fromValue(5);\n\n$sum = $computeA()-\u003eflatMap(static function ($a) use ($computeB) {\n    return $computeB()-\u003eflatMap(static function ($b) use ($a) {\n        return new Some($a + $b);\n    });\n});\n\n$sum; // Some(6)\n```\n\nNow this is already pretty terrible but imagine you want to combine the result of 3 or even 10 options, welcome in \ncallback hell.\n\nThe solution:\n\n```php\n$computeA = fn() =\u003e Option::fromValue(1);\n$computeB = fn() =\u003e Option::fromValue(5);\n\n$sum = Option::binding(static function () use ($computeA, $computeB) {\n    $a = yield $computeA();\n    $b = yield $computeB();\n    return $a + $b;\n}); \n\n$sum; // Some(6)\n```\n\nThat looks a lot more like the kind of code that you want to write! It's not perfect because we have to wrap the whole\nthing in a callable and pass that to the `binding` function, but it's much easier to read then our first example. \nEspecially if the amount of computations increases.\n\n## License\n\nMost of the source code in this project is  licensed under MIT. The `Apply\\Option` packages is derived from \n`schmittjoh/php-option` which is licensed under Apache-2.0. \n\n`SPDX-License-Identifier: Apache-2.0 AND MIT`","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimfennis%2Fapply","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftimfennis%2Fapply","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimfennis%2Fapply/lists"}