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. 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.
$maybeInt = new Maybe(new 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.
Composition of function calls
$result = c (fn ($x) => $x + 2) (123); // 125Function 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 = 250Wrap any php function
$min = c('min');
$maybeArrayOfInt = new Maybe(new 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 itOr 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", ""]); // trueclass 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
);
}
}/**
* 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"));$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); // truephpstan 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.
Feel free to add any PR, comments, issues or discussions!
See Documentation.org file (Emacs org-file).
Here will maintain a list of other libraries. Feel free to let me know of one I have missed.
- marcosh/lamphpda
- crell/fp
- loophp/repository-monadic-helper
- haskellcamargo/php-maybe-monad
- tmciver/functional-php
- phel-lang/phel-lang
- fp4php/functional
- krakphp/fn
- prolic/fpp
- phpfn/curry
- mathiasverraes/lambdalicious
- haskellcamargo/yay-partial-functions
- haskellcamargo/php-partial-function-application
- loophp/combinator
- friends-of-reactphp/partial
- fp4php/fp4php
- matteosister/php-curry
- munusphp/munus
- kapolos/pramda
- ace411/bingo-functional
- chippyash/Monad
- jasny/improved-php-function
- pitchart/transformer
- functional-php/fantasy-land
- haskellcamargo/php-church-encoding
- functional-php/pattern-matching
- quack/quack
- functional-php/trampoline
- phunkie/phunkie
- baethon/phln