diff --git a/CHANGELOG.md b/CHANGELOG.md index 40c2922..6a37c61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic versioning](http://semver.org/). - do not flip arguments on `ListL/ConcatenationMonoid` - introduce `Alt` and `Plus` typeclasses - define `ConstantSemigroup` +- fix `foldr` behavior for lists ## [2.0.0] - 2023-03-21 diff --git a/spec/ConcatenateListsWithFoldMapSpec.php b/spec/ConcatenateListsWithFoldMapSpec.php new file mode 100644 index 0000000..d87e2ad --- /dev/null +++ b/spec/ConcatenateListsWithFoldMapSpec.php @@ -0,0 +1,17 @@ +fold( + new ConcatenationMonoid(), + new ListL([[1, 2], [3, 4], [5, 6]]) + ))->toBe([1, 2, 3, 4, 5, 6]); + }); +}); diff --git a/src/Instances/ListL/ConcatenationMonoid.php b/src/Instances/ListL/ConcatenationMonoid.php index 421b355..b064ca8 100644 --- a/src/Instances/ListL/ConcatenationMonoid.php +++ b/src/Instances/ListL/ConcatenationMonoid.php @@ -27,7 +27,7 @@ public function mempty(): array * @param list $b * @return list */ - public function append($a, $b) + public function append(mixed $a, mixed $b): mixed { return [...$a, ...$b]; } diff --git a/src/Instances/ListL/ListFoldable.php b/src/Instances/ListL/ListFoldable.php index 8068b57..a4b82a1 100644 --- a/src/Instances/ListL/ListFoldable.php +++ b/src/Instances/ListL/ListFoldable.php @@ -28,14 +28,25 @@ final class ListFoldable implements Foldable */ public function foldr(callable $f, mixed $b, HK1 $a): mixed { - $aList = ListL::fromBrand($a); + $aList = ListL::fromBrand($a)->asNativeList(); - /** @psalm-suppress ImpureMethodCall */ - foreach ($aList as $aElement) { - /** @psalm-suppress ImpureFunctionCall */ - $b = $f($aElement, $b); + if ([] === $aList) { + return $b; } - return $b; + $head = array_shift($aList); + + /** + * @psalm-suppress ImpureFunctionCall + * @psalm-suppress ImpureVariable + */ + return $f( + $head, + $this->foldr( + $f, + $b, + new ListL($aList) + ) + ); } } diff --git a/src/Typeclass/Extra/ExtraFoldable.php b/src/Typeclass/Extra/ExtraFoldable.php new file mode 100644 index 0000000..bad39a7 --- /dev/null +++ b/src/Typeclass/Extra/ExtraFoldable.php @@ -0,0 +1,66 @@ + $foldable + */ + public function __construct(private readonly Foldable $foldable) + { + } + + /** + * @template A + * @template M + * @param Monoid $mMonoid + * @param callable(A): M $f + * @param HK1 $hk + * @return M + */ + public function foldMap(Monoid $mMonoid, callable $f, $hk) + { + return $this->foldable->foldr( + /** + * @param A $a + * @param M $m + * @return M + */ + static fn ($a, $m) => $mMonoid->append($f($a), $m), + $mMonoid->mempty(), + $hk + ); + } + + /** + * @template M + * @param Monoid $mMonoid + * @param HK1 $hk + * @return M + */ + public function fold(Monoid $mMonoid, $hk) + { + return $this->foldMap( + $mMonoid, + /** + * @param M $m + * @return M + */ + static fn ($m) => $m, + $hk + ); + } +}