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)1251.4k2[1 issues](https://github.com/loophp/combinator/issues)MITPHPPHP &gt;= 8CI passing

Since Jan 20Pushed 1mo 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 1mo ago

READMEChangelog (7)Dependencies (7)Versions (10)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**Apply`$``λ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`**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) -> a -> (b -> c) -> a -> d`**E**Eagle`λabcde.ab(cde)``a => b => c => d => e => a(b)(c(d)(e))``(c -> 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))``(c -> b) -> (a -> d -> c) -> a -> d -> b`**H**Hummingbird`λabc.abcb``a => b => c => a(b)(c)(b)``(a -> b -> a -> c) -> a -> b -> c`**I**Idiot`id``λa.a``a => a``a -> a`**J**Jay`λabcd.ab(adc)``a => b => c => d => a(b)(a(d)(c))``(a -> c -> d) -> a -> b -> (a -> c) -> d`**K**Kestrel`const``λab.a``a => b => a``a -> b -> a`**Ki**Kite`konst``λab.b``a => b => b``a -> b -> b`**L**Lark`λab.a(bb)``a => b => a(b(b))``(a -> a -> b) -> (a -> b)`**M**Mockingbird`λa.aa``a => a(a)``(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))``(a -> a) -> b`**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`(##)``λ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```λabcd.a((bd)(cd))``a => b => c => d => a(b(d)(c(d)))``(c -> d) -> (a -> b -> c) -> (a -> b) -> 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`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 (Apply) 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.

```php
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))
```

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))`.

```php
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] => A [1] => B [2] => C [3] => d [4] => e )
```

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 (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.

```php
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`.

```php
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();
$combine = fn(int $product): callable => fn(int $sum): string => "Sum: $sum, Product: $product";
$sum = fn(int $x): callable => fn(int $y): int => $x + $y;
$product = fn(int $x): callable => fn(int $y): int => $x * $y;
$value = 3;

// This is a bit mind-bending. The lambda is a((bd)(cd)).
// Let's find a better example. `a` must take one argument.
$format = fn(int $result): string => "Final result is: $result";
$multiply = fn(int $x): callable => fn(int $y): int => $x * $y;
$addOne = fn(int $x): int => $x + 1;
$d = 5;

// Equivalent to $format($multiply(5)($addOne(5))) -> $format(5 * 6)
echo $s2($format)($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 that can hold state. `b` is applied to `a` applied to itself applied to `b`.

```php
use loophp\combinator\Combinators;

$u = Combinators::U();
$factorialGenerator = static fn(callable $f): callable =>
    static fn(int $n): int => (0 === $n) ? 1 : $n * $f($f)($n - 1);

$factorial = $u($factorialGenerator);

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 &amp; Z (Fixed-Point) Combinators- **Purpose:** The Y and Z combinators are used to achieve recursion in languages that do not have built-in recursive syntax. They are "fixed-point" finders for functions. The Z combinator is a variant that works in strict (eagerly evaluated) languages like PHP without causing infinite loops during construction.

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

// A "generator" function that describes one step of the factorial calculation.
// It takes the recursive function ($fact) as an argument.
$factorialGenerator = static fn (Closure $fact): Closure =>
    static fn (int $n): int => (0 === $n) ? 1 : ($n * $fact($n - 1));

// The Z combinator creates a recursive factorial function from the generator.
$factorial = Combinators::Z()($factorialGenerator);

echo $factorial(6); // Outputs: 720

// The Y combinator can also be used, as this library implements it in a way
// that is safe for eager evaluation.
$fibonacciGenerator = static fn (Closure $fibo): Closure =>
    static fn (int $n): int => ($n
