diff --git a/alleycats-core/src/main/scala/alleycats/std/set.scala b/alleycats-core/src/main/scala/alleycats/std/set.scala index 9421e69aac..bff022b424 100644 --- a/alleycats-core/src/main/scala/alleycats/std/set.scala +++ b/alleycats-core/src/main/scala/alleycats/std/set.scala @@ -55,8 +55,16 @@ trait SetInstances { // If we accept Monad for Set, we can also have Alternative, as // Alternative only requires MonoidK (already accepted by cats-core) and // the Applicative that comes from Monad. - implicit val alleyCatsStdSetMonad: Monad[Set] with Alternative[Set] = - new Monad[Set] with Alternative[Set] { + implicit val alleycatsStdInstancesForSet + : Monad[Set] with Alternative[Set] with Traverse[Set] with TraverseFilter[Set] = + new Monad[Set] with Alternative[Set] with Traverse[Set] with TraverseFilter[Set] { + val traverse: Traverse[Set] = this + + def traverseFilter[G[_], A, B](fa: Set[A])(f: A => G[Option[B]])(implicit G: Applicative[G]): G[Set[B]] = + traverse + .foldRight(fa, Eval.now(G.pure(Set.empty[B])))((x, xse) => G.map2Eval(f(x), xse)((i, o) => i.fold(o)(o + _))) + .value + def pure[A](a: A): Set[A] = Set(a) override def map[A, B](fa: Set[A])(f: A => B): Set[B] = fa.map(f) def flatMap[A, B](fa: Set[A])(f: A => Set[B]): Set[B] = fa.flatMap(f) @@ -98,13 +106,7 @@ trait SetInstances { override def prependK[A](a: A, fa: Set[A]): Set[A] = fa + a override def appendK[A](fa: Set[A], a: A): Set[A] = fa + a - } - // Since iteration order is not guaranteed for sets, folds and other - // traversals may produce different results for input sets which - // appear to be the same. - implicit val alleyCatsSetTraverse: Traverse[Set] = - new Traverse[Set] { def foldLeft[A, B](fa: Set[A], b: B)(f: (B, A) => B): B = fa.foldLeft(b)(f) def foldRight[A, B](fa: Set[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = @@ -173,13 +175,10 @@ trait SetInstances { fa.collectFirst(Function.unlift(f)) } - implicit val alleyCatsSetTraverseFilter: TraverseFilter[Set] = - new TraverseFilter[Set] { - val traverse: Traverse[Set] = alleyCatsSetTraverse - - def traverseFilter[G[_], A, B](fa: Set[A])(f: A => G[Option[B]])(implicit G: Applicative[G]): G[Set[B]] = - traverse - .foldRight(fa, Eval.now(G.pure(Set.empty[B])))((x, xse) => G.map2Eval(f(x), xse)((i, o) => i.fold(o)(o + _))) - .value - } + @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") + val alleyCatsSetTraverse: Traverse[Set] = alleycatsStdInstancesForSet + @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") + val alleyCatsStdSetMonad: Monad[Set] with Alternative[Set] = alleycatsStdInstancesForSet + @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") + val alleyCatsSetTraverseFilter: TraverseFilter[Set] = alleycatsStdInstancesForSet } diff --git a/alleycats-laws/shared/src/test/scala/alleycats/tests/SetSuite.scala b/alleycats-laws/shared/src/test/scala/alleycats/tests/SetSuite.scala index c71091bc78..8b926b34c9 100644 --- a/alleycats-laws/shared/src/test/scala/alleycats/tests/SetSuite.scala +++ b/alleycats-laws/shared/src/test/scala/alleycats/tests/SetSuite.scala @@ -28,10 +28,10 @@ import cats.instances.all._ import cats.kernel.laws.discipline.SerializableTests import cats.laws.discipline.SemigroupalTests.Isomorphisms import cats.laws.discipline.arbitrary._ -import cats.laws.discipline.{AlternativeTests, ShortCircuitingTests, TraverseFilterTests} +import cats.laws.discipline.{AlternativeTests, FunctorTests, ShortCircuitingTests, TraverseFilterTests} class SetSuite extends AlleycatsSuite { - implicit val iso: Isomorphisms[Set] = Isomorphisms.invariant[Set](alleyCatsStdSetMonad) + implicit val iso: Isomorphisms[Set] = Isomorphisms.invariant[Set](alleycatsStdInstancesForSet) checkAll("FlatMapRec[Set]", FlatMapRecTests[Set].tailRecM[Int]) @@ -40,6 +40,9 @@ class SetSuite extends AlleycatsSuite { checkAll("TraverseFilter[Set]", TraverseFilterTests[Set].traverseFilter[Int, Int, Int]) checkAll("Set[Int]", AlternativeTests[Set].alternative[Int, Int, Int]) + + checkAll("Functor[Int]", FunctorTests[Set].functor[Int, Int, Int]) + checkAll("Alternative[Set]", SerializableTests.serializable(Alternative[Set])) checkAll("Set[Int]", ShortCircuitingTests[Set].traverseFilter[Int])