Skip to content

Commit

Permalink
Add traverseUnordered for Set
Browse files Browse the repository at this point in the history
  • Loading branch information
Luka Jacobowitz committed Sep 30, 2017
1 parent 965f9c2 commit fcb429d
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 4 deletions.
16 changes: 15 additions & 1 deletion core/src/main/scala/cats/data/Nested.scala
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,27 @@ private[data] sealed abstract class NestedInstances9 extends NestedInstances10 {
}
}

private[data] sealed abstract class NestedInstances10 {
private[data] sealed abstract class NestedInstances10 extends NestedInstances11 {
implicit def catsDataInvariantForNestedContravariant[F[_]: Invariant, G[_]: Contravariant]: Invariant[Nested[F, G, ?]] =
new NestedInvariant[F, G] {
val FG: Invariant[λ[α => F[G[α]]]] = Invariant[F].composeContravariant[G]
}
}

private[data] sealed abstract class NestedInstances11 extends NestedInstances12 {
implicit def catsDataCommutativeApplyForNestedContravariant[F[_]: CommutativeApply, G[_]: CommutativeApply]: CommutativeApply[Nested[F, G, ?]] =
new NestedApply[F, G] with CommutativeApply[Nested[F, G, ?]] {
val FG: Apply[λ[α => F[G[α]]]] = Apply[F].compose[G]
}
}

private[data] sealed abstract class NestedInstances12 {
implicit def catsDataCommutativeApplicativeForNestedContravariant[F[_]: CommutativeApplicative, G[_]: CommutativeApplicative]: CommutativeApplicative[Nested[F, G, ?]] =
new NestedApplicative[F, G] with CommutativeApplicative[Nested[F, G, ?]] {
val FG: Applicative[λ[α => F[G[α]]]] = Applicative[F].compose[G]
}
}

private[data] trait NestedInvariant[F[_], G[_]] extends Invariant[Nested[F, G, ?]] {
def FG: Invariant[λ[α => F[G[α]]]]

Expand Down
20 changes: 19 additions & 1 deletion core/src/main/scala/cats/data/Tuple2K.scala
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,31 @@ private[data] sealed abstract class Tuple2KInstances4 extends Tuple2KInstances5
}
}

private[data] sealed abstract class Tuple2KInstances5 {
private[data] sealed abstract class Tuple2KInstances5 extends Tuple2KInstances6 {
implicit def catsDataFunctorForTuple2K[F[_], G[_]](implicit FF: Functor[F], GG: Functor[G]): Functor[λ[α => Tuple2K[F, G, α]]] = new Tuple2KFunctor[F, G] {
def F: Functor[F] = FF
def G: Functor[G] = GG
}
}


private[data] sealed abstract class Tuple2KInstances6 extends Tuple2KInstances7 {

implicit def catsDataCommutativeApplyForTuple2K[F[_], G[_]](implicit FF: CommutativeApply[F], GG: CommutativeApply[G]): CommutativeApply[λ[α => Tuple2K[F, G, α]]] =
new Tuple2KApply[F, G] with CommutativeApply[λ[α => Tuple2K[F, G, α]]] {
def F: Apply[F] = FF
def G: Apply[G] = GG
}
}

private[data] sealed abstract class Tuple2KInstances7 {
implicit def catsDataCommutativeApplicativeForTuple2K[F[_], G[_]](implicit FF: CommutativeApplicative[F], GG: CommutativeApplicative[G]): CommutativeApplicative[λ[α => Tuple2K[F, G, α]]] =
new Tuple2KApplicative[F, G] with CommutativeApplicative[λ[α => Tuple2K[F, G, α]]] {
def F: Applicative[F] = FF
def G: Applicative[G] = GG
}
}

private[data] sealed trait Tuple2KFunctor[F[_], G[_]] extends Functor[λ[α => Tuple2K[F, G, α]]] {
def F: Functor[F]
def G: Functor[G]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ trait CommutativeApplyTests[F[_]] extends ApplyTests[F] {
}

object CommutativeApplyTests {
def apply[F[_]: CommutativeFlatMap]: CommutativeApplyTests[F] =
def apply[F[_]: CommutativeApply]: CommutativeApplyTests[F] =
new CommutativeApplyTests[F] {
def laws: CommutativeApplyLaws[F] = CommutativeApplyLaws[F]
}
Expand Down
13 changes: 13 additions & 0 deletions tests/src/test/scala/cats/tests/NestedTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,26 @@ class NestedTests extends CatsSuite {
checkAll("Apply[Nested[List, ListWrapper, ?]]", SerializableTests.serializable(Apply[Nested[List, ListWrapper, ?]]))
}

{
// CommutativeApply composition
checkAll("Nested[Option, Validated[Int, ?], ?]", CommutativeApplyTests[Nested[Option, Validated[Int, ?], ?]].commutativeApply[Int, Int, Int])
checkAll("CommutativeApply[Nested[List, ListWrapper, ?]]", SerializableTests.serializable(CommutativeApply[Nested[Option, Validated[Int, ?], ?]]))
}

{
// Applicative composition
implicit val instance = ListWrapper.applicative
checkAll("Nested[List, ListWrapper, ?]", ApplicativeTests[Nested[List, ListWrapper, ?]].applicative[Int, Int, Int])
checkAll("Applicative[Nested[List, ListWrapper, ?]]", SerializableTests.serializable(Applicative[Nested[List, ListWrapper, ?]]))
}

{
// CommutativeApplicative composition
implicit val instance = ListWrapper.applicative
checkAll("Nested[Option, Validated[Int, ?], ?]", CommutativeApplicativeTests[Nested[Option, Validated[Int, ?], ?]].commutativeApplicative[Int, Int, Int])
checkAll("CommutativeApplicative[Nested[List, ListWrapper, ?]]", SerializableTests.serializable(CommutativeApplicative[Nested[Option, Validated[Int, ?], ?]]))
}

{
//ApplicativeError composition
implicit val instance = ListWrapper.applicative
Expand Down
32 changes: 32 additions & 0 deletions tests/src/test/scala/cats/tests/SetTests.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cats
package tests

import cats.data.{Nested, Tuple2K}
import cats.laws.discipline.{FoldableTests, MonoidKTests, SerializableTests}

class SetTests extends CatsSuite {
Expand All @@ -21,6 +22,37 @@ class SetTests extends CatsSuite {
}
}

test("traverseUnordered identity") {
forAll { (si: Set[Int], f: Int => String) =>
CommutativeApplicative.traverseUnordered[Id, Int, String](si)(f) should === (si.map(f))
}
}

test("traverseUnordered sequential composition") {
forAll { (si: Set[Int], f: Int => Option[String], g: String => Option[Int]) =>
val lhs = Nested(CommutativeApplicative.traverseUnordered(si)(f).map(ss => CommutativeApplicative.traverseUnordered(ss)(g)))
val rhs = CommutativeApplicative.traverseUnordered(si)(i => Nested(f(i).map(g)))
lhs should === (rhs)
}
}

test("traverseUnordered parallel composition") {
forAll { (si: Set[Int], f: Int => Option[String], g: Int => Option[String]) =>
type Two[A] = Tuple2K[Option, Option, A]

val lhs = CommutativeApplicative.traverseUnordered(si)(i => Tuple2K(f(i), g(i)))
val rhs = Tuple2K(CommutativeApplicative.traverseUnordered(si)(f), CommutativeApplicative.traverseUnordered(si)(g))
lhs should ===(rhs)
}
}

test("traverseUnordered consistent with sequenceUnordered") {
forAll { (si: Set[Int], f: Int => String) =>
CommutativeApplicative.traverseUnordered(si)(i => f(i).valid[Int]) should
=== (CommutativeApplicative.sequenceUnordered(si.map(i => f(i).valid[Int])))
}
}

test("show keeps separate entries for items that map to identical strings"){
//note: this val name has to be the same to shadow the cats.instances instance
implicit val catsStdShowForInt: Show[Int] = Show.show(_ => "1")
Expand Down
12 changes: 11 additions & 1 deletion tests/src/test/scala/cats/tests/Tuple2KTests.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cats
package tests

import cats.data.Tuple2K
import cats.data.{Tuple2K, Validated}
import cats.functor.Contravariant
import cats.laws.discipline._
import cats.laws.discipline.arbitrary._
Expand Down Expand Up @@ -40,6 +40,16 @@ class Tuple2KTests extends CatsSuite {
checkAll("Apply[Tuple2K[ListWrapper, ListWrapper, ?]]", SerializableTests.serializable(Apply[Tuple2K[ListWrapper, ListWrapper, ?]]))
}

{
checkAll("Tuple2K[Option, Validated[Int, ?], ?]", CommutativeApplyTests[Tuple2K[Option, Validated[Int, ?], ?]].commutativeApply[Int, Int, Int])
checkAll("Apply[Tuple2K[Option, Validated[Int, ?], ?]]", SerializableTests.serializable(CommutativeApply[Tuple2K[Option, Validated[Int, ?], ?]]))
}

{
checkAll("Tuple2K[Option, Validated[Int, ?], ?]", CommutativeApplicativeTests[Tuple2K[Option, Validated[Int, ?], ?]].commutativeApplicative[Int, Int, Int])
checkAll("Applicative[Tuple2K[Option, Validated[Int, ?], ?]]", SerializableTests.serializable(CommutativeApplicative[Tuple2K[Option, Validated[Int, ?], ?]]))
}

{
implicit val functor = ListWrapper.functor
checkAll("Tuple2K[ListWrapper, ListWrapper, ?]", FunctorTests[Tuple2K[ListWrapper, ListWrapper, ?]].functor[Int, Int, Int])
Expand Down

0 comments on commit fcb429d

Please sign in to comment.