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
+ );
+ }
+}