{"id":13616459,"url":"https://github.com/marcosh/lamphpda","last_synced_at":"2025-05-16T15:03:22.001Z","repository":{"id":41204187,"uuid":"234506651","full_name":"marcosh/lamphpda","owner":"marcosh","description":"A collection of type-safe functional data structures","archived":false,"fork":false,"pushed_at":"2025-03-24T16:08:08.000Z","size":415,"stargazers_count":119,"open_issues_count":15,"forks_count":9,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-05-16T15:02:47.089Z","etag":null,"topics":["data-structures","functional-programming","hacktoberfest","php","psalm"],"latest_commit_sha":null,"homepage":"","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/marcosh.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","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,"zenodo":null}},"created_at":"2020-01-17T08:38:46.000Z","updated_at":"2025-04-08T21:20:08.000Z","dependencies_parsed_at":"2022-09-13T18:10:44.962Z","dependency_job_id":"c01faf0a-54e2-454b-8b0c-944b785aaacb","html_url":"https://github.com/marcosh/lamphpda","commit_stats":{"total_commits":340,"total_committers":6,"mean_commits":"56.666666666666664","dds":0.138235294117647,"last_synced_commit":"009c004cec922564e168b1ea5fa2c430b08f207c"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcosh%2Flamphpda","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcosh%2Flamphpda/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcosh%2Flamphpda/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcosh%2Flamphpda/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marcosh","download_url":"https://codeload.github.com/marcosh/lamphpda/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254553936,"owners_count":22090415,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["data-structures","functional-programming","hacktoberfest","php","psalm"],"created_at":"2024-08-01T20:01:28.808Z","updated_at":"2025-05-16T15:03:21.935Z","avatar_url":"https://github.com/marcosh.png","language":"PHP","funding_links":[],"categories":["PHP"],"sub_categories":[],"readme":"# lamPHPda\n\nA collection of type-safe functional data structures\n\n## Aim\n\nThe aim of this library is to provide a collection of functional data\nstructures in the most type safe way currently possible within the PHP\necosystem, still providing a generic and consistent API.\n\n## Main ideas\n\nThe two ideas which differentiate this from other functional libraries in PHP\nare:\n\n- a safe usage of sum types, following [http://marcosh.github.io/post/2017/10/27/maybe-in-php-2.html](http://marcosh.github.io/post/2017/10/27/maybe-in-php-2.html)\n- the usage of higher kinded types to increase reusability and type safety\n  (see [http://marcosh.github.io/post/2020/04/15/higher-kinded-types-php-issue.html](http://marcosh.github.io/post/2020/04/15/higher-kinded-types-php-issue.html)\n  and [http://marcosh.github.io/post/2020/04/15/higher-kinded-types-php-solution.html](http://marcosh.github.io/post/2020/04/15/higher-kinded-types-php-solution.html))\n\n## Installation\n\n```shell\ncomposer require marcosh/lamphpda\n```\n\n## Tools\n\nWe use [Psalm](https://psalm.dev/) as a type checker. It basically works as a\ncompilation step, ensuring that all the types are aligned.\n\nTo benefit from this library, it is compulsory that your code runs through a\nPsalm check.\n\n## Development\n\nThis library includes a `flake.nix` file, enabling you to access a development\nenvironment equipped with PHP 8.1 and Composer. To utilize it, simply execute\n`nix develop` within the directory. For those using `direnv`\n(with `nix-direnv`), a preconfigured `.envrc` file is also provided, which will\nautomatically load the environment upon entering the library directory.\n\n## Decision record\n\nThe relevant decisions regarding the project are collected in the [`adr`](adr) folder, following the\n[Architectural decision record](https://adr.github.io/) format\n\n## Content\n\nThe library provides several immutable data structures useful to write applications in a functional style.\n\nCurrently, the implemented data structures are:\n\n- [Maybe](src/Maybe.php), which allows modelling data which could be missing;\n- [Either](src/Either.php), which models the idea of alternative;\n- [Identity](src/Identity.php), which is just a simple wrapper\n- [LinkedList](src/LinkedList.php), which models the possibility of having multiple values;\n- [Pair](src/Pair.php), which models having two thing at the same time;\n- [Reader](src/Reader.php), which models values which depend on a context;\n- [State](src/State.php), which models values which can interact with a global state;\n- [IO](src/IO.php), which models lazy values.\n\nYou can find more details about the implementation and the idea behind each data structure in the\n[docs/data-structures folder](docs/data-structures).\n\n## How to interact with the data structures\n\nThe library is built to be extremely abstract and generic to allow extreme composability and reusability.\n\nThere are various ways which you can use to interact with the provided data structures.\n\n### Typeclasses\n\nYou can think of typeclasses as of behaviours which could be attached to a data structure. Since a data structure could\nin principle have more than one way to implement a specific behaviour (e.g., there's more than one way to use two\nintegers to compute a new integer), we can not use directly interfaces to be implemented by our data structures.\nTherefore, typeclass instances are implemented as separate independent objects implementing an interface which describes\nthe typeclass itself.\n\nFor example, the `Semigroup` typeclass, which describes the behaviour of [putting together two things of the same type\nto obtain a thing of the same type](http://marcosh.github.io/post/2020/08/21/type-equality-in-object-oriented-programming.html),\ncould be implemented as\n\n```php\n/**\n * @template A\n */\ninterface Semigroup\n{\n    /**\n     * @param A $a\n     * @param A $b\n     * @return A\n     */\n    public function append($a, $b);\n}\n```\n\nNow we can implement a `Semigroup` instance for any type we want, even for native types. For example, we could implement\na semigroup for addition between integers\n\n```php\n/**\n * @implements Semigruop\u003cint\u003e\n */\nfinal class IntAddition implements Semigroup\n{\n    /**\n     * @param int $a\n     * @param int $b\n     * @return int\n     */\n    public function append($a, $b): int\n    {\n        return $a + $b;\n    }\n}\n```\n\nThen we could use it to sum two integers\n\n```php\n(new IntAddition())-\u003eappend(1, 2); // returns 3\n```\n\nThis specific instance is not that interesting, but the fact that you could write code which depends on a generic\n`Semigroup` definitely is!\n\nThe typeclasses we are currently exposing are:\n\n- [Functor](src/Typeclass/Functor.php), which allows lifting functions of one argument to a given context;\n- [Apply](src/Typeclass/Apply.php), which allows lifting functions of any arity to a given context;\n- [Applicative](src/Typeclass/Applicative.php), which allows lifting values to a context;\n- [Alternative](src/Typeclass/Alternative.php), which models the ability of combining values wrapped in a context;\n- [Monad](src/Typeclass/Monad.php), which allows sequencing functions which return a value in a context;\n- [MonadThrow](src/Typeclass/MonadThrow.php), which allows managing exceptions in a pure way\n- [Foldable](src/Typeclass/Foldable.php), which allows to shrink a data structure to a single value;\n- [Traversable](src/Typeclass/Traversable.php), which allows transforming a data structure with a function returning values in an applicative context;\n- [Semigroup](src/Typeclass/Semigroup.php), which allows combining two values of the same type;\n- [Monoid](src/Typeclass/Monoid.php), which allows creating an identity element;\n- [Bifunctor](src/Typeclass/Bifunctor.php), which models context which depends on two covariant type variables;\n- [Profunctor](src/Typeclass/Profunctor.php), which models context which depends on a contravariant and a covariant type variable.\n\nMore details on each typeclass can be found in the [docs/typeclasses folder](docs/typeclasses).\n\n### Typeclasses and data structures\n\nAs a [design principle](adr/2021-11-22-methods-come-from-typeclasses.md) for this library, we try to expose on our data\nstructures only methods which come from a typeclass. This means that the provided data structure have a standard common\nAPI which makes use of typeclasses instances.\n\nFor example, `Either` has two `Apply` instances. To choose which one you want to use, `Either` exposes the `iapply`\nmethod which takes as first argument an instance of an `Apply` typeclass for `Either`.\n\n```php\n/**\n * @template A\n * @template B\n */\nfinal class Either\n{\n    /**\n     * @template C\n     * @param Apply\u003cEitherBrand\u003cA\u003e\u003e $apply\n     * @param HK1\u003cEitherBrand\u003cA\u003e, callable(B): C\u003e $f\n     * @return Either\u003cA, C\u003e\n     */\n    public function iapply(Apply $apply, HK1 $f): self\n}\n```\n\nWe are able to specify that a typeclass instance refers to a specific data structure using the so-called\n[`Brands`](src/Brand/Brand.php), which are nothing else that tags at the type level which enable us to simulate higher\nkinded types.\n\n### Default typeclass instances\n\nMore often than not a data structure admits only one instance of a typeclass, or there exists one which is considered\nstandard in the literature. In such cases it is quite inconvenient to sustain the burden of passing the typeclass\ninstance; to ease the pain, we expose also the method where the default typeclass instance is already provided.\n\nContinuing with the example in the previous section, `Either` exposes also a method `apply` where the `EitherApply`\ninstance is hardcoded.\n\n```php\n/**\n * @template A\n * @template B\n */\nfinal class Either\n{\n    /**\n     * @template C\n     * @param HK1\u003cEitherBrand\u003cA\u003e, callable(B): C\u003e $f\n     * @return Either\u003cA, C\u003e\n     */\n    public function apply(HK1 $f): self\n    {\n        return $this-\u003eiapply(new EitherApply(), $f);\n    }\n}\n```\n\n## Contributing\n\nIf you wish to contribute to the project, please read the [CONTRIBUTING notes](CONTRIBUTING.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcosh%2Flamphpda","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcosh%2Flamphpda","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcosh%2Flamphpda/lists"}