Skip to content

Commit 2ff62a0

Browse files
committed
Merge branch 'develop'
* develop: specify next release add Sequence::via() add deprecation notice in the documentation for Sequence::indexOf() deprecate Sequence::indexOf() use date range in license copyright typo add deprecation notice add snap documenation deprecate Set::defer() add Set::snap() remove old Set implementation directly use a Sequence as a Set implementation add Sequence::snap()
2 parents 3575877 + 1bff71b commit 2ff62a0

21 files changed

Lines changed: 1246 additions & 1377 deletions

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
# Changelog
22

3+
## 5.14.0 - 2025-04-02
4+
5+
### Added
6+
7+
- `Innmind\Immutable\Sequence::snap()`
8+
- `Innmind\Immutable\Set::snap()`
9+
- `Innmind\Immutable\Sequence::via()`
10+
11+
### Changed
12+
13+
- `Innmind\Immutable\Set` implementation now directly uses `Innmind\Immutable\Sequence`
14+
15+
### Deprecated
16+
17+
- `Innmind\Immutable\Set::defer()`
18+
- `Innmind\Immutable\Sequence::indexOf()`
19+
320
## 5.13.0 - 2025-03-23
421

522
### Added

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2015
3+
Copyright (c) 2015-present
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

docs/structures/fold.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,11 @@ $fold = Fold::with([])->flatMap(static fn($elements) => match ($someElement) {
7676

7777
## `->mapResult()`
7878

79-
Same as [`->map()`](#map) except that it will transform the _result_ value when there is one.
79+
Same as [`->map()`](#-map) except that it will transform the _result_ value when there is one.
8080

8181
## `->mapFailure()`
8282

83-
Same as [`->map()`](#map) except that it will transform the _failure_ value when there is one.
83+
Same as [`->map()`](#-map) except that it will transform the _failure_ value when there is one.
8484

8585
## `->maybe()`
8686

docs/structures/sequence.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ $sequence->indexOf(2); // Maybe::just(1)
173173
$sequence->indexOf(4); // Maybe::nothing()
174174
```
175175

176+
??? warning "Deprecated"
177+
This method will be remove in the next major version.
178+
176179
### `->find()`
177180

178181
Returns a [`Maybe`](maybe.md) object containing the first element that matches the predicate.
@@ -236,6 +239,51 @@ $squares = $ints->flatMap(fn($i) => Sequence::of($i, $i**2));
236239
$squares->equals(Sequence::ints(1, 1, 2, 4, 3, 9)); // true
237240
```
238241

242+
### `->via()`
243+
244+
This method configures the `Sequence` via the provided callable. It allows a more fluent API when the code to modify the `Sequence` lies elsewhere and may be dynamic.
245+
246+
=== "Do"
247+
```php
248+
$doubles = static fn(Sequence $sequence) => $sequence->map(
249+
static fn(int $i) => $i * 2,
250+
);
251+
252+
$sequence = Sequence::of(1, 2, 3)
253+
->via($doubles)
254+
->via($doubles);
255+
```
256+
257+
=== "Instead of"
258+
```php
259+
$doubles = static fn(Sequence $sequence) => $sequence->map(
260+
static fn(int $i) => $i * 2,
261+
);
262+
263+
$sequence = $doubles(
264+
$doubles(
265+
Sequence::of(1, 2, 3),
266+
),
267+
);
268+
```
269+
270+
In both cases it returns `#!php Sequence::of(4, 8, 12)`, but `#!php ->via()` offers a more readable experience.
271+
272+
??? tip
273+
For [lazy](#lazy) sequences the callable will be called everytime you call un unwrapping method :material-memory-arrow-down:.
274+
275+
This allows to have stateful configuration.
276+
277+
If you want the callable to be called once you need to use this strategy instead:
278+
279+
```php
280+
$sequence = Sequence::lazy($generator)
281+
->toIdentity()
282+
->map($doubles)
283+
->map($doubles)
284+
->unwrap();
285+
```
286+
239287
### `->zip()`
240288

241289
This method allows to merge 2 sequences into a new one by combining the values of the 2 into pairs.
@@ -814,3 +862,22 @@ $sequence = Sequence::lazy(function() {
814862
->map(static fn($line) => \strtoupper($line)) // still no line loaded here
815863
->memoize(); // load all lines and apply strtoupper on each
816864
```
865+
866+
### `->snap()`
867+
868+
This method indicates that the `Sequence` will be [memoized](#-memoize) when a method that needs to load the data is called.
869+
870+
```php
871+
$sequence = Sequence::lazy(function() {
872+
$stream = \fopen('some-file', 'r');
873+
while (!\feof($stream)) {
874+
yield \fgets($stream);
875+
}
876+
})
877+
->map(static fn($line) => \trim($line, "\n"))
878+
->exclude(static fn($line) => $line === '')
879+
->snap()
880+
->map(static fn($line) => \strtoupper($line)); // still no line loaded here
881+
```
882+
883+
Unlike `->memoize()`, if no code after this needs to access the data then nothing is loaded but it some does then it will load all non empty lines at once.

docs/structures/set.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ The method ask a generator that will provide the elements. Once the elements are
3030
!!! warning ""
3131
Beware of the case where the source you read the elements is not altered before the first use of the set.
3232

33+
??? warning "Deprecated"
34+
This constructor is deprecated. You should use `Set::lazy()->snap()` instead.
35+
3336
### `::lazy()`
3437

3538
This is similar to `::defer()` with the exception that the elements are not kept in memory but reloaded upon each use.
@@ -445,3 +448,22 @@ $set = Set::lazy(function() {
445448
->map(static fn($line) => \strtoupper($line)) // still no line loaded here
446449
->memoize(); // load all lines and apply strtoupper on each
447450
```
451+
452+
### `->snap()`
453+
454+
This method indicates that the `Set` will be [memoized](#-memoize) when a method that needs to load the data is called.
455+
456+
```php
457+
$sequence = Set::lazy(function() {
458+
$stream = \fopen('some-file', 'r');
459+
while (!\feof($stream)) {
460+
yield \fgets($stream);
461+
}
462+
})
463+
->map(static fn($line) => \trim($line, "\n"))
464+
->exclude(static fn($line) => $line === '')
465+
->snap()
466+
->map(static fn($line) => \strtoupper($line)); // still no line loaded here
467+
```
468+
469+
Unlike `->memoize()`, if no code after this needs to access the data then nothing is loaded but it some does then it will load all non empty lines at once.

proofs/sequence.php

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,4 +679,188 @@ static function($assert, $values) {
679679
);
680680
},
681681
);
682+
683+
yield proof(
684+
'Sequence::snap() loads a lazy sequence only once',
685+
given(
686+
Set\Type::any(),
687+
Set\Sequence::of(Set\Type::any()),
688+
Set\Type::any(),
689+
),
690+
static function($assert, $value, $rest, $last) {
691+
$loaded = 0;
692+
$sequence = Sequence::lazy(static function() use (&$loaded, $value, $rest, $last) {
693+
yield $value;
694+
yield from $rest;
695+
yield $last;
696+
697+
++$loaded;
698+
})
699+
->snap()
700+
->map(static fn($value) => [$value]);
701+
702+
$assert->same(0, $loaded);
703+
$assert->same(
704+
[$value],
705+
$sequence->first()->match(
706+
static fn($value) => $value,
707+
static fn() => null,
708+
),
709+
);
710+
$assert->same(1, $loaded);
711+
$assert->same(
712+
[$last],
713+
$sequence->last()->match(
714+
static fn($value) => $value,
715+
static fn() => null,
716+
),
717+
);
718+
$assert->same(1, $loaded);
719+
},
720+
);
721+
722+
yield proof(
723+
'Sequence::snap() loads a deferred sequence at once',
724+
given(
725+
Set\Type::any(),
726+
Set\Sequence::of(Set\Type::any()),
727+
Set\Type::any(),
728+
),
729+
static function($assert, $value, $rest, $last) {
730+
$loaded = 0;
731+
$sequence = Sequence::defer((static function() use (&$loaded, $value, $rest, $last) {
732+
yield $value;
733+
yield from $rest;
734+
yield $last;
735+
736+
++$loaded;
737+
})())
738+
->snap()
739+
->map(static fn($value) => [$value]);
740+
741+
$assert->same(0, $loaded);
742+
$assert->same(
743+
[$value],
744+
$sequence->first()->match(
745+
static fn($value) => $value,
746+
static fn() => null,
747+
),
748+
);
749+
$assert->same(1, $loaded);
750+
$assert->same(
751+
[$last],
752+
$sequence->last()->match(
753+
static fn($value) => $value,
754+
static fn() => null,
755+
),
756+
);
757+
$assert->same(1, $loaded);
758+
},
759+
);
760+
761+
yield proof(
762+
'Sequence::via()',
763+
given(
764+
Set\Sequence::of(Set\Type::any()),
765+
Set\Elements::of(
766+
static fn(array $values) => Sequence::of(...$values),
767+
static fn(array $values) => Sequence::defer(
768+
(static fn() => yield from $values)(),
769+
),
770+
static fn(array $values) => Sequence::lazy(
771+
static fn() => yield from $values,
772+
),
773+
),
774+
Set\Sequence::of(Set\Type::any()),
775+
),
776+
static function($assert, $initial, $build, $new) {
777+
$sequence = $build($initial);
778+
$sequence2 = $sequence->via(static function($sequence) use ($assert, $initial, $build, $new) {
779+
$assert->same($initial, $sequence->toList());
780+
781+
return $build($new);
782+
});
783+
784+
$assert->same($new, $sequence2->toList());
785+
},
786+
);
787+
788+
yield proof(
789+
"Sequence::via() doesn't load underlying generators",
790+
given(
791+
Set\Sequence::of(Set\Type::any()),
792+
Set\Elements::of(
793+
static fn(bool &$loaded, array $values) => Sequence::defer(
794+
(static function() use (&$loaded, $values) {
795+
yield from $values;
796+
$loaded = true;
797+
})(),
798+
),
799+
static fn(bool &$loaded, array $values) => Sequence::lazy(
800+
static function() use (&$loaded, $values) {
801+
yield from $values;
802+
$loaded = true;
803+
},
804+
),
805+
),
806+
),
807+
static function($assert, $initial, $build) {
808+
$loaded = false;
809+
$sequence = $build($loaded, $initial);
810+
$sequence2 = $sequence->via(static fn($sequence) => $sequence);
811+
812+
$assert->false($loaded);
813+
$assert->same($initial, $sequence2->toList());
814+
},
815+
);
816+
817+
yield proof(
818+
'Sequence::via() on a lazy sequence calls the function everytime the sequence is unwrapped',
819+
given(
820+
Set\Sequence::of(Set\Type::any()),
821+
),
822+
static function($assert, $values) {
823+
$loaded = 0;
824+
$sequence = Sequence::lazy(
825+
static fn() => yield from $values,
826+
);
827+
$sequence2 = $sequence->via(static function($sequence) use (&$loaded) {
828+
++$loaded;
829+
830+
return $sequence;
831+
});
832+
833+
$assert->same(0, $loaded);
834+
$assert->same($values, $sequence2->toList());
835+
$assert->same(1, $loaded);
836+
$assert->same($values, $sequence2->toList());
837+
$assert->same(2, $loaded);
838+
},
839+
);
840+
841+
yield proof(
842+
'Sequence::lazy()->snap()->via() loads the generator once',
843+
given(
844+
Set\Sequence::of(Set\Type::any()),
845+
),
846+
static function($assert, $values) {
847+
$loaded = 0;
848+
$sequence = Sequence::lazy(
849+
static fn() => yield from $values,
850+
);
851+
$sequence2 = $sequence
852+
->snap()
853+
->via(static function($sequence) use (&$loaded) {
854+
++$loaded;
855+
856+
return $sequence;
857+
});
858+
859+
$assert->same(0, $loaded);
860+
$assert->same($values, $sequence2->toList());
861+
$assert->same(1, $loaded);
862+
$assert->same($values, $sequence2->toList());
863+
$assert->same(1, $loaded);
864+
},
865+
);
682866
};

0 commit comments

Comments
 (0)