PHPackages                             thgs/functional - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. thgs/functional

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

thgs/functional
===============

a functional experiment

v0.9(1y ago)32[3 PRs](https://github.com/thgs/functional/pulls)MITPHPCI passing

Since Mar 10Pushed 4mo ago1 watchersCompare

[ Source](https://github.com/thgs/functional)[ Packagist](https://packagist.org/packages/thgs/functional)[ RSS](/packages/thgs-functional/feed)WikiDiscussions master Synced today

READMEChangelog (9)Dependencies (3)Versions (18)Used By (0)

functional
----------

[](#functional)

This is a very experimental repository where I try to see how some functional concepts can be expressed and constructed in PHP.

I tried initially to express some concepts as good as I could understand them and very quickly realised that a very very similar approach was used in [marcosh/lamphpda](https://github.com/marcosh/lamphpda). That is a more complete library.

From then on, I have deviated considerably and certain decisions are quite different, for reasons that either I still explore and I am not certain about or for different goals and priorities.

### Highlight features

[](#highlight-features)

#### Basic structures from Haskell

[](#basic-structures-from-haskell)

```
$maybeInt = Maybe::just(123);
$maybeInt = $maybeInt->fmap(fn ($x) => $x * 2);

if ($maybeInt->isJust()) {
    print $maybeInt->unwrap();
}
```

Including `Maybe`, `Either`, `IO` with instances as functors, applicative functors and monads.

#### Expression helpers

[](#expression-helpers)

Composition of function calls

```
$result = c (fn ($x) => $x + 2) (123); // 125
```

Function composition

```
$f = fn ($x) => $x + 2;
$g = fn ($x) => $x * 2;
$gf = c($f)->fmap($g); // equivalent of g(f($x))

print $gf(123);  // (123 + 2) * 2 = 250
```

Wrap any php function

```
$min = c('min');

$maybeArrayOfInt = Maybe::just(range(1,4));

$maybeMinOfArray = fmap($min, $maybeArrayOfInt);

var_dump($maybeMinOfArray->unwrap());
```

Do notation

```
// putStrLn :: String -> IO ()
$putStrLn = fn (string $x) => IO::inject(fn () => print $x . "\n");

// getLine :: IO String
$getLine = IO::inject(fn (): string => fgets(\STDIN));

$bound = dn($getLine, $putStrLn);
$bound(); // will run getLine and then bind the result to putStrLn and print it
```

Or a more elaborate example

```
dn(
    writeFile("test.txt", show (123 * 123)),
    appendFile("test.txt", "Hello!\n"),
    readFile("test.txt"),
    putStrLn(...)
)();
```

Generalised Notations

By defining the composition between the "elements"

```
function myNotation(mixed ...$elements) {
    return (new LeftToRightNotation(new CategoryOfFunctions()))->composeMany(...$elements);
}

// this will compose a function that first will evaluate the last passed "element"
$composedFunction = myNotation(
     fn (int $x): bool => $x == 16,
     fn (int $x): int  => (int) ($x / 2),
     fn (int $x): int => pow($x, 5),
     fn (array $items): int => count($items),
     array_filter(...)
);

$composedFunction(["one", "two", ""]); // true
```

#### Helpers for your tests

[](#helpers-for-your-tests)

```
class MyType implements FunctorInstance
{
    public function fmap(\Closure $f): FunctorInstance
    {
        // your code here
    }
}

class MyTypeTest
{
    // use helper traits to prove your implementation of fmap abides by the Functor Law.
    use FunctorLawsAssertions;

    public function testIsAFunctor(): void
    {
        $myType = new MyType();

        // Provide an instance and two functions for this assertion

        $this->assertInstanceIsFunctor(
            $myType,
            fn (int $x): int => $x + 2,
            fn (int $x): int => $x + 2
        );
    }
}
```

#### Wrap existing code

[](#wrap-existing-code)

```
/**
 * Create a Wrapper with an anonymous function that calls the psr3Logger from a Tuple input.
 */
$wrapper = Wrapper::withAdjustedInput(
    fn (Tuple $p) => $psr3Logger -> log ($p->fst(), $p->snd()),
);

/**
 * Let's add a prefix
 */
$prefix = 'prefixHere: ';

/**
 * Adjust the input
 */
$contextLogger = $wrapper -> adjustInput (fn (Tuple $p): Tuple => t ($prefix . $p->fst(), [$p->snd()]) );

/**
 * Adjust the output
 */
$logger = $contextLogger -> adjustOutput (fn () => time());

$currentTime = $logger (t ("Log message", "context"));
```

#### Implement typeclass instances for types

[](#implement-typeclass-instances-for-types)

```
$equalsImplementation = fn (int|float $a, int|float $b): bool  => ((int) $a) == ((int) $b);

Eq::register(
    instanceName: 'int|float',
    typePredicate: fn ($x) => is_int($x) || is_float($x),
    equals: $equalsImplementation,
    notEquals: null // derived
);

$result = equals(12.6, 12.1); // true
$result = notEquals(12.6, 13.1); // true
```

#### Loads of bugs and inconsistencies

[](#loads-of-bugs-and-inconsistencies)

phpstan is complaining, the tests are not yet fully there but I only have covered some portion of the functionality. Nevertheless, I expect there are things that might have been implemented or type hinted wrong at this point. Especially if you stress the limits of the definitions or functionality.

### Contributing

[](#contributing)

Feel free to add any PR, comments, issues or discussions!

### Documentation

[](#documentation)

See [`Documentation.org`](https://github.com/thgs/functional/blob/master/Documentation.org) file (Emacs org-file).

### Other interesting functional programming in PHP libraries/projects

[](#other-interesting-functional-programming-in-php-librariesprojects)

Here will maintain a list of other libraries. Feel free to let me know of one I have missed.

- [marcosh/lamphpda](https://github.com/marcosh/lamphpda)
- [crell/fp](https://github.com/crell/fp)
- [loophp/repository-monadic-helper](https://github.com/loophp/repository-monadic-helper)
- [haskellcamargo/php-maybe-monad](https://github.com/haskellcamargo/php-maybe-monad)
- [tmciver/functional-php](https://github.com/tmciver/functional-php)
- [phel-lang/phel-lang](https://github.com/phel-lang/phel-lang)
- [fp4php/functional](https://github.com/fp4php/functional)
- [krakphp/fn](https://github.com/krakphp/fn)
- [prolic/fpp](https://github.com/prolic/fpp)
- [phpfn/curry](https://github.com/phpfn/curry)
- [mathiasverraes/lambdalicious](https://github.com/mathiasverraes/lambdalicious)
- [haskellcamargo/yay-partial-functions](https://github.com/haskellcamargo/yay-partial-functions)
- [haskellcamargo/php-partial-function-application](https://github.com/haskellcamargo/php-partial-function-application)
- [loophp/combinator](https://github.com/loophp/combinator)
- [friends-of-reactphp/partial](https://github.com/friends-of-reactphp/partial)
- [fp4php/fp4php](https://github.com/fp4php/fp4php)
- [matteosister/php-curry](https://github.com/matteosister/php-curry)
- [munusphp/munus](https://github.com/munusphp/munus)
- [kapolos/pramda](https://github.com/kapolos/pramda)
- [ace411/bingo-functional](https://github.com/ace411/bingo-functional)
- [chippyash/Monad](https://github.com/chippyash/Monad)
- [jasny/improved-php-function](https://github.com/jasny/improved-php-function)
- [pitchart/transformer](https://github.com/pitchart/transformer)
- [functional-php/fantasy-land](https://github.com/functional-php/fantasy-land)
- [haskellcamargo/php-church-encoding](https://github.com/haskellcamargo/php-church-encoding)
- [functional-php/pattern-matching](https://github.com/functional-php/pattern-matching)
- [quack/quack](https://github.com/quack/quack)
- [functional-php/trampoline](https://github.com/functional-php/trampoline)
- [phunkie/phunkie](https://github.com/phunkie/phunkie)
- [baethon/phln](https://github.com/baethon/phln)

###  Health Score

30

—

LowBetter than 62% of packages

Maintenance63

Regular maintenance activity

Popularity6

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity36

Early-stage or recently created project

 Bus Factor1

Top contributor holds 99.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~7 days

Total

9

Last Release

418d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/08c186b51dd688533c147618687a391ac764aafcff5efc2cbb2005cc28befef6?d=identicon)[thgs](/maintainers/thgs)

---

Top Contributors

[![thgs](https://avatars.githubusercontent.com/u/8940963?v=4)](https://github.com/thgs "thgs (317 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")

---

Tags

experimentalfunctional-programmingphp

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/thgs-functional/health.svg)

```
[![Health](https://phpackages.com/badges/thgs-functional/health.svg)](https://phpackages.com/packages/thgs-functional)
```

###  Alternatives

[vsn4ik/bootstrap-checkbox

A checkbox component based on Bootstrap framework

2109.0k3](/packages/vsn4ik-bootstrap-checkbox)[uuf6429/rune

PHP Rule Engine.

7011.8k](/packages/uuf6429-rune)[nylle/php-automapper

271.4k](/packages/nylle-php-automapper)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
