From 6512b68eb0b845e939937f4f91bf8b6c2e7e5aec Mon Sep 17 00:00:00 2001 From: Mickey Donaghy Date: Tue, 8 Oct 2024 10:54:13 +0900 Subject: [PATCH 1/5] Add `unorderedFoldMapA` method --- .../main/scala/cats/UnorderedFoldable.scala | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/UnorderedFoldable.scala b/core/src/main/scala/cats/UnorderedFoldable.scala index 6a41b2a8aa..0078ffe2c8 100644 --- a/core/src/main/scala/cats/UnorderedFoldable.scala +++ b/core/src/main/scala/cats/UnorderedFoldable.scala @@ -35,6 +35,27 @@ trait UnorderedFoldable[F[_]] extends Serializable { def unorderedFold[A: CommutativeMonoid](fa: F[A]): A = unorderedFoldMap(fa)(identity) + /** + * Fold in a [[CommutativeApplicative]] context by mapping the `A` values to `G[B]`. combining + * the `B` values using the given `CommutativeMonoid[B]` instance. + * + * {{{ + * scala> import cats.UnorderedFoldable + * scala> import cats.syntax.all._ + * scala> val evenNumbers = Set(2,4,6,8,10) + * scala> val evenOpt: Int => Option[Int] = + * | i => if (i % 2 == 0) Some(i) else None + * scala> UnorderedFoldable[Set].unorderedFoldMapA(evenNumbers)(evenOpt) + * res0: Option[Int] = Some(30) + * scala> UnorderedFoldable[Set].foldMapA(evenNumbers :+ 11)(evenOpt) + * res1: Option[Int] = None + * }}} + */ + def unorderedFoldMapA[G[_], A, B](fa: F[A])( + f: A => G[B] + )(implicit G: CommutativeApplicative[G], B: CommutativeMonoid[B]): G[B] = + unorderedFoldMap(fa)(f)(CommutativeApplicative.commutativeMonoidFor) + /** * Tests if `fa` contains `v` using the `Eq` instance for `A` */ @@ -170,6 +191,10 @@ object UnorderedFoldable def unorderedFoldMap[B](f: A => B)(implicit ev$1: CommutativeMonoid[B]): B = typeClassInstance.unorderedFoldMap[A, B](self)(f) def unorderedFold(implicit ev$1: CommutativeMonoid[A]): A = typeClassInstance.unorderedFold[A](self) + def unorderedFoldMapA[G[_], B]( + f: A => G[B] + )(implicit ev$1: CommutativeApplicative[G], ev$2: CommutativeMonoid[B]): G[B] = + typeClassInstance.unorderedFoldMapA[G, A, B](self)(f) def isEmpty: Boolean = typeClassInstance.isEmpty[A](self) def nonEmpty: Boolean = typeClassInstance.nonEmpty[A](self) def exists(p: A => Boolean): Boolean = typeClassInstance.exists[A](self)(p) @@ -189,5 +214,4 @@ object UnorderedFoldable } @deprecated("Use cats.syntax object imports", "2.2.0") object nonInheritedOps extends ToUnorderedFoldableOps - } From a8ff6c7a1698e955c773b5c931c6d71975f6208f Mon Sep 17 00:00:00 2001 From: Mickey Donaghy Date: Tue, 8 Oct 2024 11:04:43 +0900 Subject: [PATCH 2/5] Call the correct method in the doctest --- core/src/main/scala/cats/UnorderedFoldable.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/UnorderedFoldable.scala b/core/src/main/scala/cats/UnorderedFoldable.scala index 0078ffe2c8..099d955ca3 100644 --- a/core/src/main/scala/cats/UnorderedFoldable.scala +++ b/core/src/main/scala/cats/UnorderedFoldable.scala @@ -47,7 +47,7 @@ trait UnorderedFoldable[F[_]] extends Serializable { * | i => if (i % 2 == 0) Some(i) else None * scala> UnorderedFoldable[Set].unorderedFoldMapA(evenNumbers)(evenOpt) * res0: Option[Int] = Some(30) - * scala> UnorderedFoldable[Set].foldMapA(evenNumbers :+ 11)(evenOpt) + * scala> UnorderedFoldable[Set].unorderedFoldMapA(evenNumbers :+ 11)(evenOpt) * res1: Option[Int] = None * }}} */ From 77d2a0f968609a686eec737d3eaaffa7111c852b Mon Sep 17 00:00:00 2001 From: Mickey Donaghy Date: Tue, 8 Oct 2024 11:10:40 +0900 Subject: [PATCH 3/5] Call a set method not a list one, that's the whole point --- core/src/main/scala/cats/UnorderedFoldable.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/UnorderedFoldable.scala b/core/src/main/scala/cats/UnorderedFoldable.scala index 099d955ca3..da17638d3a 100644 --- a/core/src/main/scala/cats/UnorderedFoldable.scala +++ b/core/src/main/scala/cats/UnorderedFoldable.scala @@ -47,7 +47,7 @@ trait UnorderedFoldable[F[_]] extends Serializable { * | i => if (i % 2 == 0) Some(i) else None * scala> UnorderedFoldable[Set].unorderedFoldMapA(evenNumbers)(evenOpt) * res0: Option[Int] = Some(30) - * scala> UnorderedFoldable[Set].unorderedFoldMapA(evenNumbers :+ 11)(evenOpt) + * scala> UnorderedFoldable[Set].unorderedFoldMapA(evenNumbers + 11)(evenOpt) * res1: Option[Int] = None * }}} */ From 035b7be498cc99108abf25783a8efa5d5dd8bc6a Mon Sep 17 00:00:00 2001 From: Mickey Donaghy Date: Wed, 9 Oct 2024 15:33:20 +0900 Subject: [PATCH 4/5] Add identity law for unorderedFoldMapA --- laws/src/main/scala/cats/laws/UnorderedFoldableLaws.scala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/laws/src/main/scala/cats/laws/UnorderedFoldableLaws.scala b/laws/src/main/scala/cats/laws/UnorderedFoldableLaws.scala index 31ce99b079..e70df54e0c 100644 --- a/laws/src/main/scala/cats/laws/UnorderedFoldableLaws.scala +++ b/laws/src/main/scala/cats/laws/UnorderedFoldableLaws.scala @@ -30,6 +30,9 @@ trait UnorderedFoldableLaws[F[_]] { def unorderedFoldConsistentWithUnorderedFoldMap[A: CommutativeMonoid](fa: F[A]): IsEq[A] = F.unorderedFoldMap(fa)(identity) <-> F.unorderedFold(fa) + def unorderedFoldMapAIdentity[A, B: CommutativeMonoid](fa: F[A], f: A => B): IsEq[B] = + F.unorderedFoldMapA[Id, A, B](fa)(f) <-> F.unorderedFoldMap(fa)(f) + def forallConsistentWithExists[A](fa: F[A], p: A => Boolean): Boolean = if (F.forall(fa)(p)) { val negationExists = F.exists(fa)(a => !p(a)) From 2fd1efd20ef80b7f0eafd0679afbc978ee84526f Mon Sep 17 00:00:00 2001 From: Mickey Donaghy Date: Thu, 10 Oct 2024 08:45:36 +0900 Subject: [PATCH 5/5] Actually test the identity law I added --- .../main/scala/cats/laws/discipline/UnorderedFoldableTests.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/laws/src/main/scala/cats/laws/discipline/UnorderedFoldableTests.scala b/laws/src/main/scala/cats/laws/discipline/UnorderedFoldableTests.scala index 4959985576..29a4e737c9 100644 --- a/laws/src/main/scala/cats/laws/discipline/UnorderedFoldableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/UnorderedFoldableTests.scala @@ -45,6 +45,7 @@ trait UnorderedFoldableTests[F[_]] extends Laws { name = "unorderedFoldable", parent = None, "unorderedFold consistent with unorderedFoldMap" -> forAll(laws.unorderedFoldConsistentWithUnorderedFoldMap[A] _), + "unorderedFoldMapA identity" -> forAll(laws.unorderedFoldMapAIdentity[A, B] _), "forall consistent with exists" -> forAll(laws.forallConsistentWithExists[A] _), "forall true if empty" -> forAll(laws.forallEmpty[A] _), "nonEmpty reference" -> forAll(laws.nonEmptyRef[A] _),