From 4f8b7e45830df15dd72d0625d2516e2b7f4832ab Mon Sep 17 00:00:00 2001 From: Emil Hotkowski Date: Sat, 30 Jul 2022 09:34:39 +0200 Subject: [PATCH 01/16] #4276 - Added traverseCollect to TraverseFilter typeclass --- core/src/main/scala/cats/TraverseFilter.scala | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/src/main/scala/cats/TraverseFilter.scala b/core/src/main/scala/cats/TraverseFilter.scala index 3d0dae6ae6..d50b8c6d88 100644 --- a/core/src/main/scala/cats/TraverseFilter.scala +++ b/core/src/main/scala/cats/TraverseFilter.scala @@ -22,6 +22,7 @@ package cats import cats.data.State +import cats.implicits.toTraverseOps import scala.collection.immutable.{HashSet, TreeSet} @@ -56,6 +57,12 @@ trait TraverseFilter[F[_]] extends FunctorFilter[F] { */ def traverseFilter[G[_], A, B](fa: F[A])(f: A => G[Option[B]])(implicit G: Applicative[G]): G[F[B]] + /** + * A combined [[traverse]] and [[collect]]. + */ + def traverseCollect[G[_], A, B](fa: F[A], f: PartialFunction[A, G[B]])(implicit F: TraverseFilter[F], G: Applicative[G]): G[F[B]] = + F.traverseFilter(fa)(a => f.lift(a).sequence) + /** * {{{ * scala> import cats.implicits._ From 4590a075f85e1e72bf599ad0ba3f3c560bfea627 Mon Sep 17 00:00:00 2001 From: Emil Hotkowski Date: Sat, 30 Jul 2022 10:23:33 +0200 Subject: [PATCH 02/16] Formatting --- core/src/main/scala/cats/TraverseFilter.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/TraverseFilter.scala b/core/src/main/scala/cats/TraverseFilter.scala index d50b8c6d88..c3952ac682 100644 --- a/core/src/main/scala/cats/TraverseFilter.scala +++ b/core/src/main/scala/cats/TraverseFilter.scala @@ -60,7 +60,10 @@ trait TraverseFilter[F[_]] extends FunctorFilter[F] { /** * A combined [[traverse]] and [[collect]]. */ - def traverseCollect[G[_], A, B](fa: F[A], f: PartialFunction[A, G[B]])(implicit F: TraverseFilter[F], G: Applicative[G]): G[F[B]] = + def traverseCollect[G[_], A, B](fa: F[A], f: PartialFunction[A, G[B]])(implicit + F: TraverseFilter[F], + G: Applicative[G] + ): G[F[B]] = F.traverseFilter(fa)(a => f.lift(a).sequence) /** From c626183893cded41d1ecabcb31e9904ee10b62b2 Mon Sep 17 00:00:00 2001 From: Emil Hotkowski Date: Sun, 31 Jul 2022 09:14:34 +0200 Subject: [PATCH 03/16] Added syntax for traverseCollect --- core/src/main/scala/cats/TraverseFilter.scala | 6 ++++-- core/src/main/scala/cats/syntax/traverseFilter.scala | 12 ++++++++++++ .../src/test/scala/cats/tests/SyntaxSuite.scala | 7 +++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/TraverseFilter.scala b/core/src/main/scala/cats/TraverseFilter.scala index c3952ac682..37aace9aef 100644 --- a/core/src/main/scala/cats/TraverseFilter.scala +++ b/core/src/main/scala/cats/TraverseFilter.scala @@ -59,12 +59,14 @@ trait TraverseFilter[F[_]] extends FunctorFilter[F] { /** * A combined [[traverse]] and [[collect]]. + * + * */ - def traverseCollect[G[_], A, B](fa: F[A], f: PartialFunction[A, G[B]])(implicit + def traverseCollect[G[_], A, B](fa: F[A])(f: PartialFunction[A, G[B]])(implicit F: TraverseFilter[F], G: Applicative[G] ): G[F[B]] = - F.traverseFilter(fa)(a => f.lift(a).sequence) + traverseFilter(fa)(a => f.lift(a).sequence) /** * {{{ diff --git a/core/src/main/scala/cats/syntax/traverseFilter.scala b/core/src/main/scala/cats/syntax/traverseFilter.scala index 20fc6a170c..b2d8e59420 100644 --- a/core/src/main/scala/cats/syntax/traverseFilter.scala +++ b/core/src/main/scala/cats/syntax/traverseFilter.scala @@ -27,6 +27,9 @@ trait TraverseFilterSyntax extends TraverseFilter.ToTraverseFilterOps private[syntax] trait TraverseFilterSyntaxBinCompat0 { implicit def toSequenceFilterOps[F[_], G[_], A](fgoa: F[G[Option[A]]]): SequenceFilterOps[F, G, A] = new SequenceFilterOps(fgoa) + + implicit def toTraverseCollectOps[F[_], G[_], A](fa: F[A]): TraverseCollectOps[F, G, A] = + new TraverseCollectOps(fa) } final class SequenceFilterOps[F[_], G[_], A](private val fgoa: F[G[Option[A]]]) extends AnyVal { @@ -41,3 +44,12 @@ final class SequenceFilterOps[F[_], G[_], A](private val fgoa: F[G[Option[A]]]) */ def sequenceFilter(implicit F: TraverseFilter[F], G: Applicative[G]): G[F[A]] = F.sequenceFilter(fgoa) } + +final class TraverseCollectOps[F[_], G[_], A](private val fa: F[A]) extends AnyVal { + + def traverseCollect[B](f: PartialFunction[A, G[B]])(implicit + F: TraverseFilter[F], + G: Applicative[G] + ): G[F[B]] = + F.traverseCollect(fa)(f) +} diff --git a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala index 432e4f5596..ac2b70ae74 100644 --- a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala @@ -580,4 +580,11 @@ object SyntaxSuite { val result: Either[A, List[B]] = f.sequenceFilter } + + def testTraverseCollect[A, B]: Unit = { + val list = mock[List[A]] + val f = mock[PartialFunction[A, Option[B]]] + + val result: Option[List[B]] = list.traverseCollect(f) + } } From f73a1868db7c7e92598d86d3ec0b85594cc1c688 Mon Sep 17 00:00:00 2001 From: Emil Hotkowski Date: Mon, 1 Aug 2022 23:47:04 +0200 Subject: [PATCH 04/16] Added proper example --- core/src/main/scala/cats/TraverseFilter.scala | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/core/src/main/scala/cats/TraverseFilter.scala b/core/src/main/scala/cats/TraverseFilter.scala index 37aace9aef..3f041b3295 100644 --- a/core/src/main/scala/cats/TraverseFilter.scala +++ b/core/src/main/scala/cats/TraverseFilter.scala @@ -60,12 +60,15 @@ trait TraverseFilter[F[_]] extends FunctorFilter[F] { /** * A combined [[traverse]] and [[collect]]. * - * + * scala> import cats.implicits._ + * scala> val m: Map[Int, String] = Map(1 -> "one", 2 -> "two") + * scala> val l: List[Int] = List(1, 2, 3, 4) + * scala> def asString: PartialFunction[Int, Eval[Option[String]]] = { case n if n % 2 == 0 => Now(m.get(n)) } + * scala> val result: Eval[List[String]] = l.traverseCollect(asString) + * scala> result.value + * res0: List[String] = List(two) */ - def traverseCollect[G[_], A, B](fa: F[A])(f: PartialFunction[A, G[B]])(implicit - F: TraverseFilter[F], - G: Applicative[G] - ): G[F[B]] = + def traverseCollect[G[_], A, B](fa: F[A])(f: PartialFunction[A, G[B]])(implicit G: Applicative[G]): G[F[B]] = traverseFilter(fa)(a => f.lift(a).sequence) /** From a226d0121dd3b554d1639411a392c20e38c6addb Mon Sep 17 00:00:00 2001 From: Emil Hotkowski Date: Tue, 2 Aug 2022 18:46:36 +0200 Subject: [PATCH 05/16] Added reference law --- laws/src/main/scala/cats/laws/TraverseFilterLaws.scala | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/laws/src/main/scala/cats/laws/TraverseFilterLaws.scala b/laws/src/main/scala/cats/laws/TraverseFilterLaws.scala index b2d0df5bf0..57248c329d 100644 --- a/laws/src/main/scala/cats/laws/TraverseFilterLaws.scala +++ b/laws/src/main/scala/cats/laws/TraverseFilterLaws.scala @@ -52,6 +52,14 @@ trait TraverseFilterLaws[F[_]] extends FunctorFilterLaws[F] { G: Monad[G] ): IsEq[G[F[B]]] = fa.traverseEither(a => f(a).map(_.toRight(e)))((_, _) => Applicative[G].unit) <-> fa.traverseFilter(f) + + def traverseCollectRef[G[_], A, B]( + fa: F[A] + )(f: PartialFunction[A, G[B]])(implicit G: Applicative[G]): IsEq[G[F[B]]] = { + val lhs = fa.traverseCollect(f) + val rhs = fa.traverseFilter(a => f.lift(a).sequence) + lhs <-> rhs + } } object TraverseFilterLaws { From 25e8bbedc448b54facd97184527c43e6c1833f98 Mon Sep 17 00:00:00 2001 From: Emil Hotkowski Date: Tue, 2 Aug 2022 23:39:32 +0200 Subject: [PATCH 06/16] Added test for a law --- core/src/main/scala/cats/TraverseFilter.scala | 4 ++-- laws/src/main/scala/cats/laws/TraverseFilterLaws.scala | 4 +--- .../scala/cats/laws/discipline/TraverseFilterTests.scala | 5 ++++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/core/src/main/scala/cats/TraverseFilter.scala b/core/src/main/scala/cats/TraverseFilter.scala index 3f041b3295..44a181a176 100644 --- a/core/src/main/scala/cats/TraverseFilter.scala +++ b/core/src/main/scala/cats/TraverseFilter.scala @@ -64,9 +64,9 @@ trait TraverseFilter[F[_]] extends FunctorFilter[F] { * scala> val m: Map[Int, String] = Map(1 -> "one", 2 -> "two") * scala> val l: List[Int] = List(1, 2, 3, 4) * scala> def asString: PartialFunction[Int, Eval[Option[String]]] = { case n if n % 2 == 0 => Now(m.get(n)) } - * scala> val result: Eval[List[String]] = l.traverseCollect(asString) + * scala> val result: Eval[List[Option[String]]] = l.traverseCollect(asString) * scala> result.value - * res0: List[String] = List(two) + * res0: List[Option[String]] = List(Some("two")) */ def traverseCollect[G[_], A, B](fa: F[A])(f: PartialFunction[A, G[B]])(implicit G: Applicative[G]): G[F[B]] = traverseFilter(fa)(a => f.lift(a).sequence) diff --git a/laws/src/main/scala/cats/laws/TraverseFilterLaws.scala b/laws/src/main/scala/cats/laws/TraverseFilterLaws.scala index 57248c329d..b59339b387 100644 --- a/laws/src/main/scala/cats/laws/TraverseFilterLaws.scala +++ b/laws/src/main/scala/cats/laws/TraverseFilterLaws.scala @@ -53,9 +53,7 @@ trait TraverseFilterLaws[F[_]] extends FunctorFilterLaws[F] { ): IsEq[G[F[B]]] = fa.traverseEither(a => f(a).map(_.toRight(e)))((_, _) => Applicative[G].unit) <-> fa.traverseFilter(f) - def traverseCollectRef[G[_], A, B]( - fa: F[A] - )(f: PartialFunction[A, G[B]])(implicit G: Applicative[G]): IsEq[G[F[B]]] = { + def traverseCollectRef[G[_], A, B](fa: F[A], f: PartialFunction[A, G[B]])(implicit G: Applicative[G]): IsEq[G[F[B]]] = { val lhs = fa.traverseCollect(f) val rhs = fa.traverseFilter(a => f.lift(a).sequence) lhs <-> rhs diff --git a/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala b/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala index 990092fc83..4a616ad938 100644 --- a/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala @@ -35,6 +35,7 @@ trait TraverseFilterTests[F[_]] extends FunctorFilterTests[F] { ArbFA: Arbitrary[F[A]], ArbFOA: Arbitrary[F[Option[A]]], ArbFABoo: Arbitrary[PartialFunction[A, B]], + ArbFAOB: Arbitrary[PartialFunction[A, Option[B]]], ArbAOB: Arbitrary[A => Option[B]], ArbAOA: Arbitrary[A => Option[A]], ArbAOOB: Arbitrary[A => Option[Option[B]]], @@ -47,6 +48,7 @@ trait TraverseFilterTests[F[_]] extends FunctorFilterTests[F] { EqFB: Eq[F[B]], EqFC: Eq[F[C]], EqGFA: Eq[Option[F[A]]], + EqGFB: Eq[Option[F[B]]], EqMNFC: Eq[Nested[Option, Option, F[C]]] ): RuleSet = new DefaultRuleSet( @@ -58,7 +60,8 @@ trait TraverseFilterTests[F[_]] extends FunctorFilterTests[F] { "filterA consistent with traverseFilter" -> forAll(laws.filterAConsistentWithTraverseFilter[Option, A] _), "traverseEither consistent with traverseFilter" -> forAll( laws.traverseEitherConsistentWithTraverseFilter[Option, F[A], A, B] _ - ) + ), + "traverseFilter ref traverseCollect" -> forAll(laws.traverseCollectRef[Option, A, B] _), ) } From 945598627d0282b56e8743b19ce66f44488dc5fb Mon Sep 17 00:00:00 2001 From: Emil Hotkowski Date: Tue, 2 Aug 2022 23:53:42 +0200 Subject: [PATCH 07/16] Formatting --- laws/src/main/scala/cats/laws/TraverseFilterLaws.scala | 4 +++- .../main/scala/cats/laws/discipline/TraverseFilterTests.scala | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/laws/src/main/scala/cats/laws/TraverseFilterLaws.scala b/laws/src/main/scala/cats/laws/TraverseFilterLaws.scala index b59339b387..f4dc4040e5 100644 --- a/laws/src/main/scala/cats/laws/TraverseFilterLaws.scala +++ b/laws/src/main/scala/cats/laws/TraverseFilterLaws.scala @@ -53,7 +53,9 @@ trait TraverseFilterLaws[F[_]] extends FunctorFilterLaws[F] { ): IsEq[G[F[B]]] = fa.traverseEither(a => f(a).map(_.toRight(e)))((_, _) => Applicative[G].unit) <-> fa.traverseFilter(f) - def traverseCollectRef[G[_], A, B](fa: F[A], f: PartialFunction[A, G[B]])(implicit G: Applicative[G]): IsEq[G[F[B]]] = { + def traverseCollectRef[G[_], A, B](fa: F[A], f: PartialFunction[A, G[B]])(implicit + G: Applicative[G] + ): IsEq[G[F[B]]] = { val lhs = fa.traverseCollect(f) val rhs = fa.traverseFilter(a => f.lift(a).sequence) lhs <-> rhs diff --git a/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala b/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala index 4a616ad938..e0519801b7 100644 --- a/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala @@ -61,7 +61,7 @@ trait TraverseFilterTests[F[_]] extends FunctorFilterTests[F] { "traverseEither consistent with traverseFilter" -> forAll( laws.traverseEitherConsistentWithTraverseFilter[Option, F[A], A, B] _ ), - "traverseFilter ref traverseCollect" -> forAll(laws.traverseCollectRef[Option, A, B] _), + "traverseFilter ref traverseCollect" -> forAll(laws.traverseCollectRef[Option, A, B] _) ) } From 2e250c5fcdc7f5d27596ee5d843e61b135e4622c Mon Sep 17 00:00:00 2001 From: Emil Hotkowski Date: Wed, 3 Aug 2022 00:31:13 +0200 Subject: [PATCH 08/16] Fixed unidoc example --- core/src/main/scala/cats/TraverseFilter.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/TraverseFilter.scala b/core/src/main/scala/cats/TraverseFilter.scala index 44a181a176..bf348ad2c7 100644 --- a/core/src/main/scala/cats/TraverseFilter.scala +++ b/core/src/main/scala/cats/TraverseFilter.scala @@ -66,7 +66,7 @@ trait TraverseFilter[F[_]] extends FunctorFilter[F] { * scala> def asString: PartialFunction[Int, Eval[Option[String]]] = { case n if n % 2 == 0 => Now(m.get(n)) } * scala> val result: Eval[List[Option[String]]] = l.traverseCollect(asString) * scala> result.value - * res0: List[Option[String]] = List(Some("two")) + * res0: List[Option[String]] = List(Some(two), None) */ def traverseCollect[G[_], A, B](fa: F[A])(f: PartialFunction[A, G[B]])(implicit G: Applicative[G]): G[F[B]] = traverseFilter(fa)(a => f.lift(a).sequence) From 6afcfaf631bf3c6f16e5deade5dfb6cbeebd1a36 Mon Sep 17 00:00:00 2001 From: Emil Hotkowski Date: Wed, 3 Aug 2022 00:59:42 +0200 Subject: [PATCH 09/16] Removed unnused props --- .../main/scala/cats/laws/discipline/TraverseFilterTests.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala b/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala index e0519801b7..ec3d968c9c 100644 --- a/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala @@ -35,7 +35,6 @@ trait TraverseFilterTests[F[_]] extends FunctorFilterTests[F] { ArbFA: Arbitrary[F[A]], ArbFOA: Arbitrary[F[Option[A]]], ArbFABoo: Arbitrary[PartialFunction[A, B]], - ArbFAOB: Arbitrary[PartialFunction[A, Option[B]]], ArbAOB: Arbitrary[A => Option[B]], ArbAOA: Arbitrary[A => Option[A]], ArbAOOB: Arbitrary[A => Option[Option[B]]], @@ -48,7 +47,6 @@ trait TraverseFilterTests[F[_]] extends FunctorFilterTests[F] { EqFB: Eq[F[B]], EqFC: Eq[F[C]], EqGFA: Eq[Option[F[A]]], - EqGFB: Eq[Option[F[B]]], EqMNFC: Eq[Nested[Option, Option, F[C]]] ): RuleSet = new DefaultRuleSet( From b2d2d676bebc2e4304ba1f64564d7b1182192a50 Mon Sep 17 00:00:00 2001 From: Emil Hotkowski Date: Wed, 3 Aug 2022 01:09:08 +0200 Subject: [PATCH 10/16] Added implicit arbitrary --- .../cats/laws/discipline/TraverseFilterTests.scala | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala b/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala index ec3d968c9c..5f22c55fc2 100644 --- a/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala @@ -48,7 +48,16 @@ trait TraverseFilterTests[F[_]] extends FunctorFilterTests[F] { EqFC: Eq[F[C]], EqGFA: Eq[Option[F[A]]], EqMNFC: Eq[Nested[Option, Option, F[C]]] - ): RuleSet = + ): RuleSet = { + implicit val arbFAOB: Arbitrary[PartialFunction[A, Option[B]]] = + Arbitrary(ArbFABoo.arbitrary.map { pfab => + { case a if pfab.isDefinedAt(a) => + val b = pfab(a) + if (((a.hashCode ^ b.hashCode) & 1) == 1) Some(b) + else None + } + }) + new DefaultRuleSet( name = "traverseFilter", parent = Some(functorFilter[A, B, C]), @@ -61,6 +70,7 @@ trait TraverseFilterTests[F[_]] extends FunctorFilterTests[F] { ), "traverseFilter ref traverseCollect" -> forAll(laws.traverseCollectRef[Option, A, B] _) ) + } } object TraverseFilterTests { From d1fa2f489d1a3341e4fd901cf4f3af0d93e464a1 Mon Sep 17 00:00:00 2001 From: Emil Hotkowski Date: Wed, 3 Aug 2022 01:20:23 +0200 Subject: [PATCH 11/16] formatting --- .../laws/discipline/TraverseFilterTests.scala | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala b/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala index 5f22c55fc2..04e4576041 100644 --- a/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala @@ -50,13 +50,14 @@ trait TraverseFilterTests[F[_]] extends FunctorFilterTests[F] { EqMNFC: Eq[Nested[Option, Option, F[C]]] ): RuleSet = { implicit val arbFAOB: Arbitrary[PartialFunction[A, Option[B]]] = - Arbitrary(ArbFABoo.arbitrary.map { pfab => - { case a if pfab.isDefinedAt(a) => - val b = pfab(a) - if (((a.hashCode ^ b.hashCode) & 1) == 1) Some(b) - else None - } - }) + Arbitrary(ArbFABoo.arbitrary.map { pfab => + { + case a if pfab.isDefinedAt(a) => + val b = pfab(a) + if (((a.hashCode ^ b.hashCode) & 1) == 1) Some(b) + else None + } + }) new DefaultRuleSet( name = "traverseFilter", From cdc49db43323df12d0d473fede1b54c6ae6ef6b7 Mon Sep 17 00:00:00 2001 From: Emil Hotkowski Date: Wed, 3 Aug 2022 02:14:53 +0200 Subject: [PATCH 12/16] Remove dependency on ops --- core/src/main/scala/cats/TraverseFilter.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/TraverseFilter.scala b/core/src/main/scala/cats/TraverseFilter.scala index bf348ad2c7..d6500d885f 100644 --- a/core/src/main/scala/cats/TraverseFilter.scala +++ b/core/src/main/scala/cats/TraverseFilter.scala @@ -22,7 +22,6 @@ package cats import cats.data.State -import cats.implicits.toTraverseOps import scala.collection.immutable.{HashSet, TreeSet} @@ -69,7 +68,7 @@ trait TraverseFilter[F[_]] extends FunctorFilter[F] { * res0: List[Option[String]] = List(Some(two), None) */ def traverseCollect[G[_], A, B](fa: F[A])(f: PartialFunction[A, G[B]])(implicit G: Applicative[G]): G[F[B]] = - traverseFilter(fa)(a => f.lift(a).sequence) + traverseFilter(fa)(a => f.lift(a).map(G.map(_)(Option(_))).getOrElse(G.pure(None))) /** * {{{ From fd876857f14b4948562c1786b824932356805123 Mon Sep 17 00:00:00 2001 From: Emil Hotkowski Date: Wed, 3 Aug 2022 05:48:18 +0200 Subject: [PATCH 13/16] Update core/src/main/scala/cats/TraverseFilter.scala Co-authored-by: Arman Bilge --- core/src/main/scala/cats/TraverseFilter.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/TraverseFilter.scala b/core/src/main/scala/cats/TraverseFilter.scala index d6500d885f..490bf33464 100644 --- a/core/src/main/scala/cats/TraverseFilter.scala +++ b/core/src/main/scala/cats/TraverseFilter.scala @@ -68,7 +68,7 @@ trait TraverseFilter[F[_]] extends FunctorFilter[F] { * res0: List[Option[String]] = List(Some(two), None) */ def traverseCollect[G[_], A, B](fa: F[A])(f: PartialFunction[A, G[B]])(implicit G: Applicative[G]): G[F[B]] = - traverseFilter(fa)(a => f.lift(a).map(G.map(_)(Option(_))).getOrElse(G.pure(None))) + traverseFilter(fa)(a => Traverse[Option].sequence(f.lift(a))) /** * {{{ From 0cd6d46a40143fa8593383f1b93fbb40d46191bf Mon Sep 17 00:00:00 2001 From: Emil Hotkowski Date: Wed, 3 Aug 2022 11:51:34 +0200 Subject: [PATCH 14/16] small optimisation for optF --- core/src/main/scala/cats/TraverseFilter.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/TraverseFilter.scala b/core/src/main/scala/cats/TraverseFilter.scala index 490bf33464..9f2d00ec72 100644 --- a/core/src/main/scala/cats/TraverseFilter.scala +++ b/core/src/main/scala/cats/TraverseFilter.scala @@ -67,8 +67,10 @@ trait TraverseFilter[F[_]] extends FunctorFilter[F] { * scala> result.value * res0: List[Option[String]] = List(Some(two), None) */ - def traverseCollect[G[_], A, B](fa: F[A])(f: PartialFunction[A, G[B]])(implicit G: Applicative[G]): G[F[B]] = - traverseFilter(fa)(a => Traverse[Option].sequence(f.lift(a))) + def traverseCollect[G[_], A, B](fa: F[A])(f: PartialFunction[A, G[B]])(implicit G: Applicative[G]): G[F[B]] = { + val optF = f.lift + traverseFilter(fa)(a => Traverse[Option].sequence(optF(a))) + } /** * {{{ From cf96c2bb2aed4da2136bf9477b3bd1d0fbd9307f Mon Sep 17 00:00:00 2001 From: Emil Hotkowski Date: Tue, 16 Aug 2022 15:56:36 +0200 Subject: [PATCH 15/16] Change to more general name --- core/src/main/scala/cats/syntax/traverseFilter.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala/cats/syntax/traverseFilter.scala b/core/src/main/scala/cats/syntax/traverseFilter.scala index b2d8e59420..fde0616d0c 100644 --- a/core/src/main/scala/cats/syntax/traverseFilter.scala +++ b/core/src/main/scala/cats/syntax/traverseFilter.scala @@ -28,8 +28,8 @@ private[syntax] trait TraverseFilterSyntaxBinCompat0 { implicit def toSequenceFilterOps[F[_], G[_], A](fgoa: F[G[Option[A]]]): SequenceFilterOps[F, G, A] = new SequenceFilterOps(fgoa) - implicit def toTraverseCollectOps[F[_], G[_], A](fa: F[A]): TraverseCollectOps[F, G, A] = - new TraverseCollectOps(fa) + implicit def toTraverseFilterOps[F[_], G[_], A](fa: F[A]): TraverseFilterOps[F, G, A] = + new TraverseFilterOps(fa) } final class SequenceFilterOps[F[_], G[_], A](private val fgoa: F[G[Option[A]]]) extends AnyVal { @@ -45,7 +45,7 @@ final class SequenceFilterOps[F[_], G[_], A](private val fgoa: F[G[Option[A]]]) def sequenceFilter(implicit F: TraverseFilter[F], G: Applicative[G]): G[F[A]] = F.sequenceFilter(fgoa) } -final class TraverseCollectOps[F[_], G[_], A](private val fa: F[A]) extends AnyVal { +final class TraverseFilterOps[F[_], G[_], A](private val fa: F[A]) extends AnyVal { def traverseCollect[B](f: PartialFunction[A, G[B]])(implicit F: TraverseFilter[F], From 8b7dcb628f8b284100b227a2179c7e284c995d99 Mon Sep 17 00:00:00 2001 From: Emil Hotkowski Date: Wed, 17 Aug 2022 10:49:13 +0200 Subject: [PATCH 16/16] Update laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala Co-authored-by: Arman Bilge --- .../main/scala/cats/laws/discipline/TraverseFilterTests.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala b/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala index 04e4576041..d24d3d81ba 100644 --- a/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/TraverseFilterTests.scala @@ -69,7 +69,7 @@ trait TraverseFilterTests[F[_]] extends FunctorFilterTests[F] { "traverseEither consistent with traverseFilter" -> forAll( laws.traverseEitherConsistentWithTraverseFilter[Option, F[A], A, B] _ ), - "traverseFilter ref traverseCollect" -> forAll(laws.traverseCollectRef[Option, A, B] _) + "traverseCollect reference" -> forAll(laws.traverseCollectRef[Option, A, B] _) ) } }