Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
* develop:
  specify next release
  remove useless method
  add proof on lazy/deferred Identity::flatMap()
  add Identity::toSequence()
  adapt the laziness of the identity based on the sequence laziness
  add Identity::lazy() and ::defer()
  • Loading branch information
Baptouuuu committed Jun 27, 2024
2 parents d861ab3 + cbbc8f0 commit 4fc9114
Show file tree
Hide file tree
Showing 13 changed files with 444 additions and 27 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## 5.8.0 - 2024-06-27

### Added

- `Innmind\Immutable\Identity::lazy()`
- `Innmind\Immutable\Identity::defer()`
- `Innmind\Immutable\Identity::toSequence()`

### Changed

- `Innmind\Immutable\Sequence::toIdentity()` returns a lazy, deferred or in memory `Identity` based on the kind of `Sequence`

## 5.7.0 - 2024-06-25

### Added
Expand Down
130 changes: 120 additions & 10 deletions proofs/identity.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<?php
declare(strict_types = 1);

use Innmind\Immutable\Identity;
use Innmind\Immutable\{
Identity,
Sequence,
};
use Innmind\BlackBox\Set;

return static function() {
Expand Down Expand Up @@ -38,16 +41,62 @@
Set\Type::any(),
Set\Type::any(),
),
static fn($assert, $initial, $expected) => $assert->same(
$expected,
Identity::of($initial)
->flatMap(static function($value) use ($assert, $initial, $expected) {
$assert->same($initial, $value);
static function($assert, $initial, $expected) {
$assert->same(
$expected,
Identity::of($initial)
->flatMap(static function($value) use ($assert, $initial, $expected) {
$assert->same($initial, $value);

return Identity::of($expected);
})
->unwrap(),
),
return Identity::of($expected);
})
->unwrap(),
);

$loaded = 0;
$identity = Identity::defer(static function() use (&$loaded, $initial) {
$loaded++;

return $initial;
})->flatMap(static function($value) use ($assert, $initial, $expected) {
$assert->same($initial, $value);

return Identity::of($expected);
});
$assert->same(0, $loaded);
$assert->same(
$expected,
$identity->unwrap(),
);
$assert->same(1, $loaded);
$assert->same(
$expected,
$identity->unwrap(),
);
$assert->same(1, $loaded);

$loaded = 0;
$identity = Identity::lazy(static function() use (&$loaded, $initial) {
$loaded++;

return $initial;
})->flatMap(static function($value) use ($assert, $initial, $expected) {
$assert->same($initial, $value);

return Identity::of($expected);
});
$assert->same(0, $loaded);
$assert->same(
$expected,
$identity->unwrap(),
);
$assert->same(1, $loaded);
$assert->same(
$expected,
$identity->unwrap(),
);
$assert->same(2, $loaded);
},
);

yield proof(
Expand All @@ -71,4 +120,65 @@
->unwrap(),
),
);

yield proof(
'Identity::toSequence()',
given(Set\Sequence::of(Set\Type::any())),
static function($assert, $values) {
$inMemory = Sequence::of(...$values);

$assert->same(
$values,
$inMemory
->toIdentity()
->toSequence()
->flatMap(static fn($sequence) => $sequence)
->toList(),
);

$loaded = 0;
$deferred = Sequence::defer((static function() use (&$loaded, $values) {
yield from $values;
$loaded++;
})());
$sequence = $deferred
->toIdentity()
->toSequence()
->flatMap(static fn($sequence) => $sequence);

$assert->same(0, $loaded);
$assert->same(
$values,
$sequence->toList(),
);
$assert->same(1, $loaded);
$assert->same(
$values,
$sequence->toList(),
);
$assert->same(1, $loaded);

$loaded = 0;
$lazy = Sequence::lazy(static function() use (&$loaded, $values) {
yield from $values;
$loaded++;
});
$sequence = $lazy
->toIdentity()
->toSequence()
->flatMap(static fn($sequence) => $sequence);

$assert->same(0, $loaded);
$assert->same(
$values,
$sequence->toList(),
);
$assert->same(1, $loaded);
$assert->same(
$values,
$sequence->toList(),
);
$assert->same(2, $loaded);
},
);
};
14 changes: 9 additions & 5 deletions proofs/sequence.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@
use Innmind\BlackBox\Set;

return static function() {
yield test(
yield proof(
'Sequence::toIdentity()',
static function($assert) {
$sequence = Sequence::of();
given(Set\Sequence::of(Set\Type::any())),
static function($assert, $values) {
$sequence = Sequence::of(...$values);

$assert->same(
$sequence,
$sequence->toIdentity()->unwrap(),
$sequence->toList(),
$sequence
->toIdentity()
->unwrap()
->toList(),
);
},
);
Expand Down
69 changes: 58 additions & 11 deletions src/Identity.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,28 @@

namespace Innmind\Immutable;

use Innmind\Immutable\Identity\{
Implementation,
InMemory,
Lazy,
Defer,
};

/**
* @psalm-immutable
* @template T
*/
final class Identity
{
/** @var T */
private mixed $value;
/** @var Implementation<T> */
private Implementation $implementation;

/**
* @param T $value
* @param Implementation<T> $implementation
*/
private function __construct(mixed $value)
private function __construct(Implementation $implementation)
{
$this->value = $value;
$this->implementation = $implementation;
}

/**
Expand All @@ -30,7 +37,41 @@ private function __construct(mixed $value)
*/
public static function of(mixed $value): self
{
return new self($value);
return new self(new InMemory($value));
}

/**
* When using a lazy computation all transformations via map and flatMap
* will be applied when calling unwrap. Each call to unwrap will call again
* all transformations.
*
* @psalm-pure
* @template A
*
* @param callable(): A $value
*
* @return self<A>
*/
public static function lazy(callable $value): self
{
return new self(new Lazy($value));
}

/**
* When using a deferred computation all transformations via map and flatMap
* will be applied when calling unwrap. The value is computed once and all
* calls to unwrap will return the same value.
*
* @psalm-pure
* @template A
*
* @param callable(): A $value
*
* @return self<A>
*/
public static function defer(callable $value): self
{
return new self(new Defer($value));
}

/**
Expand All @@ -42,8 +83,7 @@ public static function of(mixed $value): self
*/
public function map(callable $map): self
{
/** @psalm-suppress ImpureFunctionCall */
return new self($map($this->value));
return new self($this->implementation->map($map));
}

/**
Expand All @@ -55,15 +95,22 @@ public function map(callable $map): self
*/
public function flatMap(callable $map): self
{
/** @psalm-suppress ImpureFunctionCall */
return $map($this->value);
return $this->implementation->flatMap($map);
}

/**
* @return Sequence<T>
*/
public function toSequence(): Sequence
{
return $this->implementation->toSequence();
}

/**
* @return T
*/
public function unwrap(): mixed
{
return $this->value;
return $this->implementation->unwrap();
}
}
67 changes: 67 additions & 0 deletions src/Identity/Defer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php
declare(strict_types = 1);

namespace Innmind\Immutable\Identity;

use Innmind\Immutable\{
Identity,
Sequence,
};

/**
* @psalm-immutable
* @template T
* @implements Implementation<T>
*/
final class Defer implements Implementation
{
/** @var callable(): T */
private $value;
private bool $loaded = false;
/** @var ?T */
private mixed $computed = null;

/**
* @param callable(): T $value
*/
public function __construct(callable $value)
{
$this->value = $value;
}

public function map(callable $map): self
{
/** @psalm-suppress ImpureFunctionCall */
return new self(fn() => $map($this->unwrap()));
}

public function flatMap(callable $map): Identity
{
/** @psalm-suppress ImpureFunctionCall */
return Identity::lazy(fn() => $map($this->unwrap())->unwrap());
}

public function toSequence(): Sequence
{
/** @psalm-suppress ImpureFunctionCall */
return Sequence::defer((fn() => yield $this->unwrap())());
}

public function unwrap(): mixed
{
if ($this->loaded) {
/** @var T */
return $this->computed;
}

/**
* @psalm-suppress InaccessibleProperty
* @psalm-suppress ImpureFunctionCall
*/
$this->computed = ($this->value)();
/** @psalm-suppress InaccessibleProperty */
$this->loaded = true;

return $this->computed;
}
}
Loading

0 comments on commit 4fc9114

Please sign in to comment.