Skip to content

Repository files navigation

Pattern Matching

pattern-matching CIStyleCICode CoverageAverage time to resolve an issuePercentage of issues still openChat on Gitter

Pattern matching is the process of checking a series of token against a pattern. It is different from pattern recognition as the match needs to be exact. The process does not only match as a switch statement does, it also assigns the value a bit like the list construct in PHP, a process called destructuring.

Most functional languages implement it as a core feature. Here is are some small examples in Haskell:

fact:: (Integrala) =>a->a
fact 0=1
fact n = n * fact (n-1)
head:: [a] ->ahead xs =case xs of[]->error"empty list"
(x:_) -> x
firstThree:: [a] -> (a, a, a)
firstThree (x:y:z:_) = (x, y, z)
firstThree _ =error"need at least 3 elements"

If you want to read more about the topic, you can head over to Wikipedia : Pattern matching

Installation

composer require functional-php/pattern-matching

Basic Usage

As we cannot extend the syntax of PHP, the choice was made to use a syntax based on arrays. The key representes the pattern and the value is the function to call with the value or a constant if you want to do nothing with it.

Let's see how we could implement our 3 Haskell examples:

useFunctionalPHP\PatternMatchingasm;
$fact = m\func([
'0' => 1,
'n' => function($n) use(&$fact) {
return$n * $fact($n - 1);
}
]);
$head = m\func([
'(x:_)' => function($x) { return$x; },
'_' => function() { thrownewRuntimeException('empty list'); }
]);
$firstThree= m\func([
'(x:y:z:_)' => function($x, $y, $z) { return [$x, $y, $z]; },
'_' => function() { thrownewRuntimeException('need at least 3 elements'); }
]);

You can also use the match function if you want to have a beefed up version of the switch statement or if you don't like anonymous functions:

useFunctionalPHP\PatternMatchingasm;
functionfactorial($n) {
returnm\pmatch([
'0' => 1,
'n' => function($n) use(&$fact) {
return$n * factorial($n - 1);
}
], $n);
}
echom\pmatch([
'"toto"' => 'first',
'[a, [b, c], d]' => 'second',
'[a, _, (x:xs), c]' => 'third',
'_' => 'default',
], [1, 2, ['a', 'b'], true]);
// third

If you are just interested in destructuring your values, there is also a helper for that:

useFunctionalPHP\PatternMatchingasm;
print_r(m\extract([1, 2, ['a', 'b'], true], '[a, _, (x:xs), c]'));
// Array (// [a] => 1// [x] => a// [xs] => Array ( [0] => b )// [c] => 1// )

Patterns

Here is a quick recap of the available patterns:

NameFormatExample
ConstantAny scalar value (int, float, string, boolean)1.0, 42, "test"
Variableidentifiera, name, anything
Array[<pattern>, ..., <pattern>][], [a], [a, b, c]
Cons(identifier:list-identifier)(x:xs), (x:y:z:xs)
Wildcard__
Asidentifier@(<pattern>)all@(x:xs)

Testing

You can run the test suite for the library using:

composer test

A test report will be available in the reports directory.

Contributing

Any contribution welcome :

  • Ideas
  • Pull requests
  • Issues

About

Pattern matching for PHP with automatic destructuring.

Resources

Stars

82 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages