PHPackages                             loophp/combinator - 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. loophp/combinator

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

loophp/combinator
=================

A curated list of combinators

2.0.2(4y ago)1271.4k2[1 issues](https://github.com/loophp/combinator/issues)MITPHPPHP &gt;= 8CI passing

Since Jan 20Pushed 2w ago5 watchersCompare

[ Source](https://github.com/loophp/combinator)[ Packagist](https://packagist.org/packages/loophp/combinator)[ GitHub Sponsors](https://github.com/drupol)[ Fund](https://www.paypal.me/drupol)[ RSS](/packages/loophp-combinator/feed)WikiDiscussions master Synced yesterday

READMEChangelog (7)Dependencies (7)Versions (11)Used By (0)

[![Latest Stable Version](https://camo.githubusercontent.com/7114e8cdaf4949e7cca77f8e3a880289659631a36178ce5fd762e33ea6379267/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6c6f6f7068702f636f6d62696e61746f722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/loophp/combinator)[![GitHub stars](https://camo.githubusercontent.com/977eb29a04608c30b68975d76cfb073d58cd0c6b1c185dd0e8a1699855c681e5/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f73746172732f6c6f6f7068702f636f6d62696e61746f722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/loophp/combinator) [![Total Downloads](https://camo.githubusercontent.com/f18f115d2c01eb42e269f9cc56a5076c3dbba0c86df499edc26afea4c98a796b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6c6f6f7068702f636f6d62696e61746f722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/loophp/combinator)[![GitHub Workflow Status](https://camo.githubusercontent.com/e6fa8bebc42a792ae12c1f9744e33a969b2c9fe48888293a4455c60ccd89a1d2/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6c6f6f7068702f636f6d62696e61746f722f74657374732e796d6c3f6272616e63683d6d6173746572267374796c653d666c61742d737175617265)](https://github.com/loophp/combinator/actions)[![Scrutinizer code quality](https://camo.githubusercontent.com/dc5f93bc8a8a2128f407d3eed45247301b8afb0fdc92d804411e84a06c5d5380/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f7175616c6974792f672f6c6f6f7068702f636f6d62696e61746f722f6d61737465722e7376673f7374796c653d666c61742d737175617265)](https://scrutinizer-ci.com/g/loophp/combinator/?branch=master)[![Type Coverage](https://camo.githubusercontent.com/618d231cd246992c25629e2b5c5220788df9ead097e4779f44f7e9374da232dc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f64796e616d69632f6a736f6e3f7374796c653d666c61742d73717561726526636f6c6f723d636f6c6f72266c6162656c3d54797065253230636f7665726167652671756572793d6d6573736167652675726c3d687474707325334125324625324673686570686572642e6465762532466769746875622532466c6f6f706870253246636f6d62696e61746f72253246636f766572616765)](https://shepherd.dev/github/loophp/combinator) [![Code Coverage](https://camo.githubusercontent.com/b2ad2888f6e12e09aa28155bfd387e4035a5fce04dce09cc8bfed8d8754a570c/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f636f7665726167652f672f6c6f6f7068702f636f6d62696e61746f722f6d61737465722e7376673f7374796c653d666c61742d737175617265)](https://scrutinizer-ci.com/g/loophp/combinator/?branch=master)[![License](https://camo.githubusercontent.com/3145d13a7e04860b474fa79dc716ac1a776947e9dfaa8aaed99f171b318063f5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6c6f6f7068702f636f6d62696e61746f722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/loophp/combinator) [![Donate!](https://camo.githubusercontent.com/a71f45de7e408be2477113d166e9ee94c90bbf814a1373fd154aa5b6652302de/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f53706f6e736f722d4769746875622d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](https://github.com/sponsors/drupol)

Combinator
==========

[](#combinator)

This package provides a comprehensive collection of well-known combinators for PHP, enabling a more declarative, [point-free programming style](https://en.wikipedia.org/wiki/Tacit_programming).

Description
-----------

[](#description)

A combinator is a [higher-order function](https://en.wikipedia.org/wiki/Higher-order_function) that uses only function application and previously defined combinators to define a result from its arguments. This concept was introduced by [Moses Schönfinkel](https://en.wikipedia.org/wiki/Moses_Sch%C3%B6nfinkel) in 1920 and later developed by [Haskell Curry](https://en.wikipedia.org/wiki/Haskell_Curry).

In computer science, combinatory logic serves as a theoretical model of computation and is a cornerstone of [functional programming](https://en.wikipedia.org/wiki/Functional_programming) language design. The core idea is to build complex functions without ever having to mention variables.

### Why use Combinators?

[](#why-use-combinators)

Using combinators can help you:

- **Write cleaner, more declarative code:** By abstracting away function composition and argument manipulation, your code can become more readable and expressive.
- **Avoid temporary variables:** Combinators provide powerful ways to pipe data through a series of functions in a clean, fluent manner.
- **Explore functional programming:** This library provides a practical way to learn about and experiment with fundamental concepts of functional programming and lambda calculus, right within PHP.

Requirements
------------

[](#requirements)

- PHP &gt;= 8.0

Installation
------------

[](#installation)

You can install the package via Composer:

```
composer require loophp/combinator
```

Available Combinators
---------------------

[](#available-combinators)

The following is a list of the combinators available in this package.

NameAliasHaskellLambda CalculusTerm Definition (JS-like)Type**A**Applicator`$``λab.ab``a => b => a(b)``(a -> b) -> a -> b`**B**Bluebird`.``λabc.a(bc)``a => b => c => a(b(c))``(b -> c) -> (a -> b) -> a -> c`**B₁**Blackbird`...``λabcd.a(bcd)``a => b => c => d => a(b(c)(d))``(c -> d) -> (a -> b -> c) -> a -> b -> d`**C**Cardinal`flip``λabc.acb``a => b => c => a(c)(b)``(a -> b -> c) -> b -> a -> c`**D**Dove`λabcd.ab(cd)``a => b => c => d => a(b)(c(d))``(b -> c -> d) -> b -> (a -> c) -> a -> d`**E**Eagle`λabcde.ab(cde)``a => b => c => d => e => a(b)(c(d)(e))``(a -> d -> e) -> a -> (b -> c -> d) -> b -> c -> e`**F**Finch`λabc.cba``a => b => c => c(b)(a)``a -> b -> (b -> a -> c) -> c`**G**Goldfinch`λabcd.ad(bc)``a => b => c => d => a(d)(b(c))``(a -> b -> c) -> (d -> b) -> d -> a -> c`**H**Hummingbird`λabc.abcb``a => b => c => a(b)(c)(b)``(a -> b -> a -> c) -> a -> b -> c`**I**Identity (Idiot)`id``λa.a``a => a``a -> a`**J**Jay`λabcd.ab(adc)``a => b => c => d => a(b)(a(d)(c))``(a -> b -> b) -> a -> b -> a -> b`**K**Kestrel`const``λab.a``a => b => a``a -> b -> a`**Ki**Kite`flip const``λab.b``a => b => b``a -> b -> b`**L**Lark`λab.a(bb)``a => b => a(b(b))``*`**M**Mockingbird`λa.aa``a => a(a)``*`**O**Owl`λab.b(ab)``a => b => b(a(b))``((a -> b) -> a) -> (a -> b) -> b`**Omega**Ω`λa.(aa)(aa)``a => (a(a))(a(a))``*`**Φ**Phoenix`λabcd.a(bd)(cd)``a => b => c => d => a(b(d))(c(d))``(b -> c -> d) -> (a -> b) -> (a -> c) -> a -> d`**Ψ**Psi`on``λabcd.a(bc)(bd)``a => b => c => d => a(b(c))(b(d))``(b -> b -> c) -> (a -> b) -> a -> a -> c`**Q**Queer`flip (.)``λabc.b(ac)``a => b => c => b(a(c))``(a -> b) -> (b -> c) -> a -> c`**R**Robin`λabc.bca``a => b => c => b(c)(a)``a -> (b -> a -> c) -> b -> c`**S**Starling```λabc.ac(bc)``a => b => c => a(c)(b(c))``(a -> b -> c) -> (a -> b) -> a -> c`**S'**S Prime`λabc.a(bc)c``a => b => c => a(b(c))(c)``(b -> a -> c) -> (a -> b) -> a -> c`**S₂**S-Two`liftA2``λabcd.a(bd)(cd)``a => b => c => d => a(b(d))(c(d))``(b -> c -> d) -> (a -> b) -> (a -> c) -> a -> d`**T**Thrush`(&)``λab.ba``a => b => b(a)``a -> (a -> b) -> b`**U**Turing`λab.b(aab)``a => b => b(a(a)(b))``((a -> b) -> b) -> (a -> b) -> b`**V**Vireo`λabc.cab``a => b => c => c(a)(b)``a -> b -> (a -> b -> c) -> c`**W**Warbler`λab.abb``a => b => a(b)(b)``(a -> a -> b) -> a -> b`**Y**Y-Fixed point`fix``λf.(λx.f(xx))(λx.f(xx))``f => (x => f(x(x)))(x => f(x(x)))``(a -> a) -> a`**Z**Z-Fixed point`fix``λf.(λx.f(λv.xxv))(λx.f(λv.xxv))``f => (x => f(v => x(x)(v)))(x => f(v => x(x)(v)))``(a -> a) -> a`> `*` indicates a combinator that is not simply typed because it relies on self-application.

Combinator by Example
---------------------

[](#combinator-by-example)

Click on any combinator below to see a practical usage example. All combinators are invokable classes, but the easiest way to access them is through the `loophp\combinator\Combinators` facade, which statically provides each one.

A (Applicator) Combinator- **Lambda:** `λab.ab`
- **Purpose:** Applies a function `a` to an argument `b`. In Haskell, this is the `$` operator. It can help reduce the number of parentheses in complex expressions.

```
use loophp\combinator\Combinators;

$a = Combinators::A();
$strlen = 'strlen';
$string = 'hello world';

// Instead of $strlen($string)
echo $a($strlen)($string); // Outputs: 11
```

B (Bluebird) Combinator- **Lambda:** `λabc.a(bc)`
- **Purpose:** Function composition. It takes two functions, `a` and `b`, and a value `c`, and applies `a` to the result of `b` applied to `c`. This is `.` in Haskell.

```
use loophp\combinator\Combinators;

$b = Combinators::B();
$addOne = fn(int $x): int => $x + 1;
$multiplyByTwo = fn(int $x): int => $x * 2;

// Create a new function: multiply by two, then add one.
$composed = $b($addOne)($multiplyByTwo);

echo $composed(5); // Outputs: 11 (which is 1 + (2 * 5))
```

B₁ (Blackbird) Combinator- **Lambda:** `λabcd.a(bcd)`
- **Purpose:** Extended function composition for three functions: `a(b(c(d)))`.

```
use loophp\combinator\Combinators;

$blackbird = Combinators::Blackbird();
$wrapInP = fn(string $s): string => "$s";
$toUpper = 'strtoupper';
$addExclamation = fn(string $s): string => "$s!";

$format = $blackbird($wrapInP)($toUpper)($addExclamation);

echo $format('hello'); // Outputs: HELLO!
```

C (Cardinal) Combinator- **Lambda:** `λabc.acb`
- **Purpose:** Flips arguments. It takes a function `a` and two arguments `b`and `c`, and applies `a` with `c` as the first argument and `b` as the second. This is `flip` in Haskell.

```
use loophp\combinator\Combinators;

$c = Combinators::C();
$divide = fn(int $x, int $y): float => $x / $y;

$flippedDivide = $c($divide);

echo $flippedDivide(2)(10); // Outputs: 5 (same as $divide(10, 2))
```

D (Dove) Combinator- **Lambda:** `λabcd.ab(cd)`
- **Purpose:** Composes two functions and their arguments: `a(b)(c(d))`.

```
use loophp\combinator\Combinators;

$d = Combinators::D();
$add = fn(int $x): callable => fn(int $y): int => $x + $y;
$multiply = fn(int $x): callable => fn(int $y): int => $x * $y;

// Calculates ( (2 + 3) + (4 * 5) ) using curried functions
echo $d($add)($add(2)(3))($multiply(4))(5); // Outputs: 25
```

E (Eagle) Combinator- **Lambda:** `λabcde.ab(cde)`
- **Purpose:** Five-argument composition, useful for deeply nested function calls: `a(b)(c(d(e)))`.

```
use loophp\combinator\Combinators;

$e = Combinators::E();
$add = fn(int $x): callable => fn(int $y): int => $x + $y;
$multiplyByTwo = fn(int $x): int => $x * 2;
$addOne = fn(int $x): int => $x + 1;

// Equivalent to: $add(10)(($multiplyByTwo($addOne(5))))
echo $e($add)(10)($multiplyByTwo)($addOne)(5); // Outputs: 22
```

F (Finch) Combinator- **Lambda:** `λabc.cba`
- **Purpose:** Reverses the application order. Applies `c` to `b`, and then to `a`.

```
use loophp\combinator\Combinators;

$f = Combinators::F();
$concat = fn(string $a): callable => fn(string $b): string => $a . $b;

// Instead of $concat(' world')('hello')
echo $f('hello')(' world')($concat); // Outputs: " worldhello"
```

G (Goldfinch) Combinator- **Lambda:** `λabcd.ad(bc)`
- **Purpose:** Applies arguments in a unique order: `a(d)(b(c))`.

```
use loophp\combinator\Combinators;

$g = Combinators::G();
$merge = fn(array $a): callable => fn(array $b): array => array_merge($a, $b);
$mapToUpper = fn(array $a): array => array_map('strtoupper', $a);

// Equivalent to $merge(['d', 'e'])(($mapToUpper(['a', 'b', 'c'])))
$result = $g($merge)($mapToUpper)(['a', 'b', 'c'])(['d', 'e']);
print_r($result); // Outputs: Array ( [0] => d [1] => e [2] => A [3] => B [4] => C )
```

H (Hummingbird) Combinator- **Lambda:** `λabc.abcb`
- **Purpose:** Applies a three-argument function, but uses the second argument twice: `a(b)(c)(b)`.

```
use loophp\combinator\Combinators;

$h = Combinators::H();
$wrap = fn(string $tag): callable => fn(string $content): callable => fn(string $closingTag): string => "$content";

// Uses 'div' as both the opening and closing tag.
$wrapInDiv = $h($wrap)('div');

echo $wrapInDiv('Hello'); // Outputs: Hello
```

I (Identity / Idiot) Combinator- **Lambda:** `λa.a`
- **Purpose:** The identity function. It returns whatever argument it receives. This is `id` in Haskell.

```
use loophp\combinator\Combinators;

$i = Combinators::I();

echo $i('Hello World'); // Outputs: Hello World
echo $i(42);            // Outputs: 42
```

J (Jay) Combinator- **Lambda:** `λabcd.ab(adc)`
- **Purpose:** A complex combinator useful for specific recursive or state-passing scenarios: `a(b)(a(d)(c))`.

```
use loophp\combinator\Combinators;

$j = Combinators::J();
$log = fn(string $prefix): callable => fn(string $message): string => "[$prefix] $message";

// Creates a nested log message
// Equivalent to $log('INFO')($log('USER')('action'))
echo $j($log)('INFO')('action')('USER'); // Outputs: [INFO] [USER] action
```

K (Kestrel) Combinator- **Lambda:** `λab.a`
- **Purpose:** The constant function. It takes two arguments and always returns the first. This is `const` in Haskell.

```
use loophp\combinator\Combinators;

$k = Combinators::K();
$alwaysReturns5 = $k(5);

echo $alwaysReturns5('foo'); // Outputs: 5
echo $alwaysReturns5(123);   // Outputs: 5
```

Ki (Kite) Combinator- **Lambda:** `λab.b`
- **Purpose:** The opposite of the Kestrel. It takes two arguments and always returns the second.

```
use loophp\combinator\Combinators;

$ki = Combinators::Ki();
$getSecond = $ki('ignored');

echo $getSecond('hello'); // Outputs: hello
echo $getSecond(true);    // Outputs: 1 (for true)
```

L (Lark) Combinator- **Lambda:** `λab.a(bb)`
- **Purpose:** Applies function `a` to the result of function `b` applied to itself. This requires `b` to be a function that can meaningfully accept itself as an argument.

```
use loophp\combinator\Combinators;

$l = Combinators::L();
$inspectType = fn(mixed $arg): string => "Argument is of type: " . gettype($arg);
$selfApplicable = fn(callable $c): string => "I am a function.";

// Equivalent to $inspectType($selfApplicable($selfApplicable))
echo $l($inspectType)($selfApplicable); // Outputs: Argument is of type: string
```

M (Mockingbird) Combinator- **Lambda:** `λa.aa`
- **Purpose:** Self-application (also known as the `ω` combinator). It applies its single argument (which must be a function) to itself.

```
use loophp\combinator\Combinators;

$m = Combinators::M();
$describe = fn(callable $c): string => "This is a closure.";

// Applies the $describe function to itself.
echo $m($describe); // Outputs: This is a closure.
```

O (Owl) Combinator- **Lambda:** `λab.b(ab)`
- **Purpose:** A peculiar form of composition, `b(a(b))`. Useful in specific recursive algorithms or data structure manipulations.

```
use loophp\combinator\Combinators;

$o = Combinators::O();
// A curried function to prepend to an array
$prepend = fn(mixed $item): callable => fn(array $list): array => [$item, ...$list];
$reverse = 'array_reverse';

// Equivalent to $reverse($prepend(3)([1, 2])) -> $reverse([3, 1, 2])
$result = $o($prepend)([1, 2])($reverse)(3);
print_r($result); // Outputs: Array ( [0] => 2 [1] => 1 [2] => 3 )
```

Omega (Ω) Combinator- **Lambda:** `λa.(aa)(aa)`
- **Purpose:** The divergent combinator. It is constructed from the Mockingbird (`M`) as `MM`. When applied to *any* function, it creates an infinitely recursive call that will exhaust memory. **Do not run this code.**

```
// This will cause a fatal error due to infinite recursion.
// $omega = Combinators::Omega();
// $omega(fn($x) => $x);
```

Φ (Phoenix) Combinator- **Lambda:** `λabcd.a(bd)(cd)`
- **Purpose:** Distributes an argument `d` across two functions `b` and `c`, then combines the results with function `a`.

```
use loophp\combinator\Combinators;

$phoenix = Combinators::Phoenix();
$add = fn(int $x): callable => fn(int $y): int => $x + $y;
$multiplyByTwo = fn(int $x): int => $x * 2;
$multiplyByThree = fn(int $x): int => $x * 3;

// Calculates (2 * 10) + (3 * 10)
$calculate = $phoenix($add)($multiplyByTwo)($multiplyByThree);

echo $calculate(10); // Outputs: 50
```

Ψ (Psi) Combinator- **Lambda:** `λabcd.a(bc)(bd)`
- **Purpose:** Another distribution combinator, but this one distributes a function `b` over two arguments `c` and `d`.

```
use loophp\combinator\Combinators;

$psi = Combinators::Psi();
$makePair = fn(string $a): callable => fn(string $b): string => "($a, $b)";
$getName = fn(array $user): string => $user['name'];
$getEmail = fn(array $user): string => $user['email'];
$user = ['name' => 'John', 'email' => 'john@example.com'];

// Equivalent to $makePair($getName($user))($getEmail($user))
echo $psi($makePair)($getName)($getEmail)($user); // Outputs: (John, john@example.com)
```

Q (Queer) Combinator- **Lambda:** `λabc.b(ac)`
- **Purpose:** A different form of composition, applying `b` to the result of `a` applied to `c`.

```
use loophp\combinator\Combinators;

$q = Combinators::Q();
$addOne = fn(int $x): int => $x + 1;
$multiplyByTwo = fn(int $x): int => $x * 2;

// Equivalent to $multiplyByTwo($addOne(5))
$composed = $q($addOne)($multiplyByTwo);

echo $composed(5); // Outputs: 12
```

R (Robin) Combinator- **Lambda:** `λabc.bca`
- **Purpose:** Reorders arguments for a two-argument function `b`.

```
use loophp\combinator\Combinators;

$r = Combinators::R();
$divide = fn(int $x): callable => fn(int $y): float => $x / $y;

// Equivalent to $divide(10)(2)
echo $r(2)($divide)(10); // Outputs: 5
```

S (Starling) Combinator- **Lambda:** `λabc.ac(bc)`
- **Purpose:** The substitution combinator. It applies a third argument `c` to both `a` and `b`, then applies the result of `a(c)` to the result of `b(c)`. It is fundamental to combinatory logic.

```
use loophp\combinator\Combinators;

$s = Combinators::S();
$add = fn(int $x): callable => fn(int $y): int => $x + $y;
$square = fn(int $x): int => $x * $x;

// Equivalent to $add($x)($square($x)) where $x is 3. So 3 + (3*3)
echo $s($add)($square)(3); // Outputs: 12
```

S' (S Prime) Combinator- **Lambda:** `λabc.a(bc)c`
- **Purpose:** A variation of the Starling that provides the final argument `c`to the outer function `a` as well. Useful for functions that need both the result of an operation and the original value, such as logging or debugging.

```
use loophp\combinator\Combinators;

$s_ = Combinators::S_();
$log = fn(string $result): callable => fn(string $original): string => "Input '$original' produced '$result'";
$transform = 'strtoupper';

// Equivalent to $log(strtoupper('hello'))('hello')
$logTransformation = $s_($log)($transform);

echo $logTransformation('hello'); // Outputs: Input 'hello' produced 'HELLO'
```

S₂ (S-Two) Combinator- **Lambda:** `λabcd.a(bd)(cd)`
- **Purpose:** Applies two different functions `b` and `c` to the same data `d`, and then combines their results with a third function `a`. In Haskell, this is similar to `liftA2`.

```
use loophp\combinator\Combinators;

$s2 = Combinators::S2();

$applyAndFormat = fn(callable $operation): callable => fn(int $value): string => "Final result is: " . $operation($value);
$multiply = fn(int $x): callable => fn(int $y): int => $x * $y;
$addOne = fn(int $x): int => $x + 1;
$d = 5;

// Equivalent to $applyAndFormat($multiply(5))($addOne(5)) -> 5 * 6
echo $s2($applyAndFormat)($multiply)($addOne)($d); // Outputs: Final result is: 30
```

T (Thrush) Combinator- **Lambda:** `λab.ba`
- **Purpose:** Reverse application. Applies function `b` to argument `a`. This is `(&)` in Haskell and is useful for data-last programming styles.

```
use loophp\combinator\Combinators;

$t = Combinators::T();
$multiplyByTwo = fn(int $x): int => $x * 2;

// Instead of $multiplyByTwo(5)
echo $t(5)($multiplyByTwo); // Outputs: 10
```

U (Turing) Combinator- **Lambda:** `λab.b(aab)`
- **Purpose:** A fixed-point combinator. `U(f)(g) = g(f(f)(g))`. In strict (eager) PHP, recursion requires the step function to call `$self($self)`explicitly and a seed callable (here: `I`) as the second argument.

```
use loophp\combinator\Combinators;

$u = Combinators::U();

// The step function threads self-application to enable recursion.
// $self($self)($g) is evaluated lazily (inside the closure body).
$factStep = fn(callable $self) => fn(callable $g): callable =>
    fn(int $n): int => $n === 0 ? 1 : $n * $self($self)($g)($n - 1);

// Pass I (identity) as the seed: U(factStep)(I) = I(factStep(factStep)(I)) = factStep(factStep)(I)
$factorial = $u($factStep)(Combinators::I());

echo $factorial(5); // Outputs: 120
```

V (Vireo) Combinator- **Lambda:** `λabc.cab`
- **Purpose:** Argument swapping. Given `c`, `a`, `b`, it calls `c(a)(b)`.

```
use loophp\combinator\Combinators;

$v = Combinators::V();
$str_replace = 'str_replace';
$search = 'foo';
$replace = 'bar';

// Creates a function that replaces 'foo' with 'bar' in a given subject string.
$replaceFoo = $v($search)($replace)($str_replace);

echo $replaceFoo('this is foo'); // Outputs: this is bar
```

W (Warbler) Combinator- **Lambda:** `λab.abb`
- **Purpose:** Duplicates an argument. It applies function `a` to argument `b`twice.

```
use loophp\combinator\Combinators;

$w = Combinators::W();
$add = fn(int $x): callable => fn(int $y): int => $x + $y;

// Equivalent to $add(5)(5)
echo $w($add)(5); // Outputs: 10
```

Y (Y-Fixed point) Combinator- **Lambda:** `λf.(λx.f(xx))(λx.f(xx))`
- **Purpose:** Creates a recursive function from a generator function without naming the recursive function directly.

```
use loophp\combinator\Combinators;
use Closure;

$factorialGenerator = static fn (Closure $fact): Closure =>
    static fn (int $n): int => (1 >= $n) ? 1 : $n * $fact($n - 1);

$factorial = Combinators::Y()($factorialGenerator);
echo $factorial(6); // Outputs: 720
```

Z (Z-Fixed point) Combinator- **Lambda:** `λf.(λx.f(λv.xxv))(λx.f(λv.xxv))`
- **Purpose:** Creates a recursive function from a generator function using an eta-expanded recursive callback, which is suitable for strict evaluation.

```
use loophp\combinator\Combinators;
use Closure;

$factorialGenerator = static fn (Closure $fact): Closure =>
    static fn (): Closure =>
        static fn (int $n): int => (1 >= $n) ? 1 : $n * $fact()()($n - 1);

$factorial = Combinators::Z()($factorialGenerator);
echo $factorial()(6); // Outputs: 720
```

Suggested reading and resources
-------------------------------

[](#suggested-reading-and-resources)

- [To Mock a Mockingbird](https://en.wikipedia.org/wiki/To_Mock_a_Mockingbird)
-
-
- [https://en.wikipedia.org/wiki/Combinatory\_logic](https://en.wikipedia.org/wiki/Combinatory_logic)
-
-

Contributing
------------

[](#contributing)

Feel free to contribute by sending pull requests. We are a usually very responsive team and we will help you going through your pull request from the beginning to the end.

For some reasons, if you can't contribute to the code and willing to help, sponsoring is a good, sound and safe way to show us some gratitude for the hours we invested in this package.

Sponsor me on [Github](https://github.com/sponsors/drupol) and/or any of [the contributors](https://github.com/loophp/combinator/graphs/contributors).

### Thanks

[](#thanks)

- [Marco Pivetta](https://github.com/ocramius)

### Authors

[](#authors)

- [Pol Dellaiera](https://not-a-number.io/)

Changelog
---------

[](#changelog)

See [CHANGELOG.md](https://github.com/loophp/combinator/blob/master/CHANGELOG.md) for a changelog based on [git commits](https://github.com/loophp/combinator/commits/master). For more detailed changelogs, please check [the release changelogs](https://github.com/loophp/combinator/releases).

###  Health Score

46

—

FairBetter than 92% of packages

Maintenance63

Regular maintenance activity

Popularity29

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity64

Established project with proven stability

 Bus Factor1

Top contributor holds 91% 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 ~80 days

Recently: every ~136 days

Total

8

Last Release

1795d ago

Major Versions

1.2.0 → 2.0.02020-10-21

PHP version history (2 changes)1.0.0PHP &gt;= 7.1.3

2.0.2PHP &gt;= 8

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/252042?v=4)[Pol Dellaiera](/maintainers/drupol)[@drupol](https://github.com/drupol)

---

Top Contributors

[![drupol](https://avatars.githubusercontent.com/u/252042?v=4)](https://github.com/drupol "drupol (162 commits)")[![renovate[bot]](https://avatars.githubusercontent.com/in/2740?v=4)](https://github.com/renovate[bot] "renovate[bot] (14 commits)")[![rehno-lindeque](https://avatars.githubusercontent.com/u/337811?v=4)](https://github.com/rehno-lindeque "rehno-lindeque (1 commits)")[![zoomlogo](https://avatars.githubusercontent.com/u/64531844?v=4)](https://github.com/zoomlogo "zoomlogo (1 commits)")

---

Tags

combinatorcombinatory-logiceducationalfunctional-programmingfunctional-programmingeducationalcombinatorcombinatory logic

###  Code Quality

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/loophp-combinator/health.svg)

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

###  Alternatives

[react/partial

Partial function application.

115386.5k13](/packages/react-partial)[mpetrovich/dash

A functional programming library for PHP. Inspired by Underscore, Lodash, and Ramda.

10330.0k1](/packages/mpetrovich-dash)[marcosh/lamphpda

A collection of functional programming data structures

12214.5k4](/packages/marcosh-lamphpda)[chemem/bingo-functional

A simple functional programming library.

707.0k3](/packages/chemem-bingo-functional)[daveross/functional-programming-utils

Functional Programming utilities for PHP 5.4+

225.2k](/packages/daveross-functional-programming-utils)[pitchart/transformer

A transducers implementation in PHP, with OOP powers

1017.0k](/packages/pitchart-transformer)

PHPackages © 2026

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