Skip to content

Commit 615821b

Browse files
authored
Merge pull request #50 from fp4php/v5
2 parents f08c58f + 2b5e8ea commit 615821b

File tree

430 files changed

+29182
-11992
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

430 files changed

+29182
-11992
lines changed

.github/workflows/php.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
- uses: actions/checkout@v2
4848
- uses: shivammathur/setup-php@v2
4949
with:
50-
php-version: '8.0'
50+
php-version: '8.1'
5151
coverage: xdebug
5252

5353
- name: Restore cached composer dependencies

README.md

Lines changed: 69 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ PHP Functional Programming library. Monads and common use functions.
1010
- ### [Streams](doc/Streams.md)
1111
- ### [Monads](doc/Monads.md)
1212
- ### [Functions](doc/Functions.md)
13-
13+
- ### [Combinators](doc/Combinators.md)
1414

1515
## Installation
1616

@@ -21,35 +21,45 @@ $ composer require fp4php/functional
2121
```
2222

2323
### Enable psalm plugin (optional)
24-
To improve type inference
24+
25+
Read more about [plugin](doc/Psalm.md).
2526

2627
```console
28+
$ composer require --dev fp4php/psalm-toolkit
2729
$ vendor/bin/psalm-plugin enable fp4php/functional
2830
```
2931

3032
## Overview
31-
Type safe and concise.
33+
Typesafe and concise.
3234

3335
Powerful combination: Collections + Option monad.
3436
```php
37+
<?php
38+
39+
use Fp\Collections\ArrayList;
40+
use Fp\Functional\Option\Option;
41+
42+
use function Fp\Evidence\of;
43+
use function Fp\Evidence\proveString;
44+
3545
class PgSqlCurrencyArrayType extends Type
3646
{
3747
public function convertToDatabaseValue($value, AbstractPlatform $platform): string
3848
{
3949
$currencies = Option::fromNullable($value)
40-
->filter(fn(mixed $raw) => is_iterable($raw))
50+
->filter(is_iterable(...))
4151
->getOrElse([]);
4252

4353
return ArrayList::collect($currencies)
44-
->filterOf(Currency::class)
54+
->flatMap(of(Currency::class))
4555
->map(fn(Currency $currency) => $currency->getCurrencyCode())
4656
->mkString('{', ',', '}');
4757
}
4858

4959
/**
50-
* @return Seq<Currency>
60+
* @return ArrayList<Currency>
5161
*/
52-
public function convertToPHPValue($value, AbstractPlatform $platform): Seq
62+
public function convertToPHPValue($value, AbstractPlatform $platform): ArrayList
5363
{
5464
$csv = Option::fromNullable($value)
5565
->flatMap(proveString(...))
@@ -75,6 +85,10 @@ class PgSqlCurrencyArrayType extends Type
7585

7686
- Type safety
7787
```php
88+
<?php
89+
90+
use Fp\Collections\NonEmptyLinkedList;
91+
7892
/**
7993
* Inferred type is NonEmptyLinkedList<1|2|3>
8094
*/
@@ -95,6 +109,12 @@ $mappedCollection = $collection->map(fn($elem) => $elem - 1);
95109
$filteredCollection = $mappedCollection->filter(fn(int $elem) => $elem > 0);
96110
```
97111
```php
112+
<?php
113+
114+
use Tests\Mock\Foo;
115+
use Tests\Mock\Bar;
116+
use Fp\Collections\NonEmptyArrayList;
117+
98118
$source = [new Foo(1), null, new Bar(2)];
99119

100120
/**
@@ -115,13 +135,17 @@ $onlyFoos = $withoutNulls->filter(fn($elem) => $elem instanceof Foo);
115135

116136
- Covariance
117137
```php
138+
<?php
139+
140+
use Fp\Collections\NonEmptyLinkedList;
141+
118142
class User {}
119143
class Admin extends User {}
120144

121145
/**
122-
* @param NonEmptyCollection<User> $collection
146+
* @param NonEmptyLinkedList<User> $collection
123147
*/
124-
function acceptUsers(NonEmptyCollection $collection): void {}
148+
function acceptUsers(NonEmptyLinkedList $collection): void {}
125149

126150
/**
127151
* @var NonEmptyLinkedList<Admin> $collection
@@ -137,6 +161,10 @@ acceptUsers($collection);
137161

138162
- Immutability
139163
```php
164+
<?php
165+
166+
use Fp\Collections\LinkedList;
167+
140168
$originalCollection = LinkedList::collect([1, 2, 3]);
141169

142170
/**
@@ -152,22 +180,22 @@ $mappedCollection = $prependedCollection->map(fn(int $elem) => $elem + 1);
152180

153181
- Null safety
154182
```php
183+
<?php
184+
185+
use Fp\Functional\Option\Option;
186+
use Fp\Collections\ArrayList;
187+
155188
/**
156-
* @var Collection<int> $emptyCollection
189+
* @var ArrayList<int> $collection
157190
*/
158-
$emptyCollection = getEmptyCollection();
159-
160-
$resultWithDefaultValue = $emptyCollection
161-
->reduce(fn(int $accumulator, int $element) => $accumulator + $element)
162-
->getOrElse(0);
191+
$collection = getCollection();
163192

164193
/**
165194
* @return Option<float>
166195
*/
167-
function div(int $a, int $b): Option {
168-
return 0 === $b
169-
? Option::none()
170-
: Option::some($a / $b)
196+
function div(int $a, int $b): Option
197+
{
198+
return Option::when(0 !== $b, fn() => $a / $b);
171199
}
172200

173201
/**
@@ -177,33 +205,43 @@ function div(int $a, int $b): Option {
177205
* In this case the execution will short circuit (stop)
178206
* and no Null Pointer Exception will be thrown.
179207
*/
180-
$emptyCollection
208+
$collection
181209
->first(fn(int $elem) => $elem > 0)
182210
->map(fn(int $elem) => $elem + 1)
183211
->flatMap(fn(int $elem) => div($elem, $elem - 1))
184212
->getOrElse(0)
185213
```
186214

187-
- Type assertions with Option monad via [PHP generators](https://www.php.net/manual/en/language.generators.syntax.php) based [do-notation](https://en.wikibooks.org/wiki/Haskell/do_notation) implementation
215+
- [Do-notation](https://en.wikibooks.org/wiki/Haskell/do_notation) via [PHP generators](https://www.php.net/manual/en/language.generators.syntax.php):
216+
188217
```php
218+
<?php
219+
220+
use Tests\Mock\Foo;
221+
use Fp\Functional\Option\Option;
222+
223+
use function Fp\Evidence\proveTrue;
224+
use function Fp\Evidence\proveNonEmptyList;
225+
189226
/**
190227
* Inferred type is Option<Foo>
191228
*/
192229
$maybeFooMaybeNot = Option::do(function() use ($untrusted) {
230+
// If $untrusted is not null then bind this value to $notNull
193231
$notNull = yield Option::fromNullable($untrusted);
194-
yield proveTrue(is_array($notNull)); // Inferred type is array<array-key, mixed>
195-
$list = yield proveList($notNull); // Inferred type is list<mixed>
196-
$nonEmptyList = yield proveNonEmptyList($list); // Inferred type is non-empty-list<mixed>
197-
$nonEmptyListOfFoo = yield proveNonEmptyListOf($nonEmptyList, Foo::class); // Inferred type is non-empty-list<Foo>
198-
$firstFoo = $nonEmptyListOfFoo[0]; // Inferred type is Foo
232+
233+
// If $notNull is non-empty-list<Tests\Mock\Foo> then bind this value to $nonEmptyListOfFoo
234+
$nonEmptyList = yield proveNonEmptyList($notNull, of(Foo::class));
235+
236+
// Continue computation if $nonEmptyList contains only one element
237+
yield proveTrue(1 === count($nonEmptyList));
199238

200-
return $firstFoo; // I'm sure it's Foo object
239+
// I'm sure it's Foo object
240+
return $nonEmptyList[0];
201241
});
202242

203-
/**
204-
* Inferred type is Foo
205-
*/
206-
$foo = $maybeFooMaybeNot->getOrCall(fn() => new Foo(0))
243+
// Inferred type is Tests\Mock\Foo
244+
$foo = $maybeFooMaybeNot->getOrCall(fn() => new Foo(0));
207245
```
208246

209247

@@ -215,7 +253,6 @@ $foo = $maybeFooMaybeNot->getOrCall(fn() => new Foo(0))
215253
```console
216254
$ sudo apt install pandoc
217255
```
218-
219256
2) Generate **doc** from **src**
220257
```console
221258
$ make

0 commit comments

Comments
 (0)