Combinator
A curated list of combinators
Install / Use
/learn @loophp/CombinatorREADME
[![Latest Stable Version][latest stable version]][1] [![GitHub stars][github stars]][1] [![Total Downloads][total downloads]][1] [![GitHub Workflow Status][github workflow status]][2] [![Scrutinizer code quality][code quality]][3] [![Type Coverage][type coverage]][4] [![Code Coverage][code coverage]][3] [![License][license]][1] [![Donate!][donate github]][github sponsors link]
Combinator
This package provides a comprehensive collection of well-known combinators for PHP, enabling a more declarative, [point-free programming style].
Description
A combinator is a [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] in 1920 and later developed by [Haskell Curry].
In computer science, combinatory logic serves as a theoretical model of computation and is a cornerstone of [functional programming] language design. The core idea is to build complex functions without ever having to mention variables.
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
- PHP >= 8.0
Installation
You can install the package via Composer:
composer require loophp/combinator
Available Combinators
The following is a list of the combinators available in this package.
| Name | Alias | Haskell | Lambda Calculus | Term 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
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.
- Lambda:
λab.ab - Purpose: Applies a function
ato an argumentb. 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
```</details>
<details>
<summary>B (Bluebird) Combinator</summary>
* **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))
</details>
<details>
<summary>Blackbird Combinator</summary>
- 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 => "<p>$s</p>";
$toUpper = 'strtoupper';
$addExclamation = fn(string $s): string => "$s!";
$format = $blackbird($wrapInP)($toUpper)($addExclamation);
echo $format('hello'); // Outputs: <p>HELLO!</p>
</details>
<details>
<summary>C (Cardinal) Combinator</summary>
- Lambda:
λabc.acb - Purpose: Flips arguments. It takes a function
aand two argumentsbandc, and appliesawithcas the first argument andbas the second. This isflipin Haskell.
use loophp\combinator\Combinators;
$c = Combinators::
