Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XorTInstances + cleanup tests #1106

Merged
merged 6 commits into from
Jun 17, 2016
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions core/src/main/scala/cats/data/Xor.scala
Original file line number Diff line number Diff line change
@@ -179,6 +179,10 @@ sealed abstract class Xor[+A, +B] extends Product with Serializable {
a => s"Xor.Left(${AA.show(a)})",
b => s"Xor.Right(${BB.show(b)})"
)

def ap[AA >: A, BB >: B, C](that: AA Xor (BB => C)): AA Xor C = that.flatMap(
f => this.map(a => f(a))
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: I think this could simply be that.flatMap(this.map)

}

object Xor extends XorInstances with XorFunctions {
@@ -240,6 +244,7 @@ private[data] sealed abstract class XorInstances extends XorInstances1 {
def foldLeft[B, C](fa: A Xor B, c: C)(f: (C, B) => C): C = fa.foldLeft(c)(f)
def foldRight[B, C](fa: A Xor B, lc: Eval[C])(f: (B, Eval[C]) => Eval[C]): Eval[C] = fa.foldRight(lc)(f)
def flatMap[B, C](fa: A Xor B)(f: B => A Xor C): A Xor C = fa.flatMap(f)
override def ap[B, C](x: A Xor (B => C))(y: A Xor B): A Xor C = y.ap(x)
def pure[B](b: B): A Xor B = Xor.right(b)
@tailrec def tailRecM[B, C](b: B)(f: B => A Xor (B Xor C)): A Xor C =
f(b) match {
51 changes: 34 additions & 17 deletions core/src/main/scala/cats/data/XorT.scala
Original file line number Diff line number Diff line change
@@ -241,14 +241,17 @@ private[data] abstract class XorTInstances extends XorTInstances1 {
val F0: Traverse[F] = F
}

implicit def xortTransLift[E]: TransLift.Aux[XorT[?[_], E, ?], Functor] =
implicit def catsDataTransLiftForXorT[E]: TransLift.Aux[XorT[?[_], E, ?], Functor] =
new TransLift[XorT[?[_], E, ?]] {
type TC[M[_]] = Functor[M]

def liftT[M[_]: Functor, A](ma: M[A]): XorT[M,E,A] =
XorT(Functor[M].map(ma)(Xor.right))
}

implicit def catsMonoidForXorT[F[_], L, A](implicit F: Monoid[F[L Xor A]]): Monoid[XorT[F, L, A]] =
new XorTMonoid[F, L, A] { implicit val F0 = F }

}

private[data] abstract class XorTInstances1 extends XorTInstances2 {
@@ -258,7 +261,10 @@ private[data] abstract class XorTInstances1 extends XorTInstances2 {
implicit val L0 = L
new XorTMonadFilter[F, L] { implicit val F = F0; implicit val L = L0 }
}
*/
*/

implicit def catsSemigroupForXorT[F[_], L, A](implicit F: Semigroup[F[L Xor A]]): Semigroup[XorT[F, L, A]] =
new XorTSemigroup[F, L, A] { implicit val F0 = F }

implicit def catsDataFoldableForXorT[F[_], L](implicit F: Foldable[F]): Foldable[XorT[F, L, ?]] =
new XorTFoldable[F, L] {
@@ -282,19 +288,11 @@ private[data] abstract class XorTInstances2 extends XorTInstances3 {
}

private[data] abstract class XorTInstances3 extends XorTInstances4 {
implicit def catsDataMonadErrorForXorT[F[_], L](implicit F: Monad[F]): MonadError[XorT[F, L, ?], L] = {
implicit val F0 = F
implicit def catsDataMonadErrorForXorT[F[_], L](implicit F0: Monad[F]): MonadError[XorT[F, L, ?], L] =
new XorTMonadError[F, L] { implicit val F = F0 }
}

implicit def catsDataSemigroupKForXorT[F[_], L](implicit F: Monad[F]): SemigroupK[XorT[F, L, ?]] =
new SemigroupK[XorT[F,L,?]] {
def combineK[A](x: XorT[F,L,A], y: XorT[F, L, A]): XorT[F, L, A] =
XorT(F.flatMap(x.value) {
case l @ Xor.Left(_) => y.value
case r @ Xor.Right(_) => F.pure(r)
})
}
implicit def catsDataSemigroupKForXorT[F[_], L](implicit F0: Monad[F]): SemigroupK[XorT[F, L, ?]] =
new XorTSemigroupK[F, L] { implicit val F = F0 }

implicit def catsDataEqForXorT[F[_], L, R](implicit F: Eq[F[L Xor R]]): Eq[XorT[F, L, R]] =
new XorTEq[F, L, R] {
@@ -303,10 +301,28 @@ private[data] abstract class XorTInstances3 extends XorTInstances4 {
}

private[data] abstract class XorTInstances4 {
implicit def catsDataFunctorForXorT[F[_], L](implicit F: Functor[F]): Functor[XorT[F, L, ?]] = {
implicit val F0 = F
implicit def catsDataFunctorForXorT[F[_], L](implicit F0: Functor[F]): Functor[XorT[F, L, ?]] =
new XorTFunctor[F, L] { implicit val F = F0 }
}
}

private[data] trait XorTSemigroup[F[_], L, A] extends Semigroup[XorT[F, L, A]] {
implicit val F0: Semigroup[F[L Xor A]]
def combine(x: XorT[F, L ,A], y: XorT[F, L , A]): XorT[F, L , A] =
XorT(F0.combine(x.value, y.value))
}

private[data] trait XorTMonoid[F[_], L, A] extends Monoid[XorT[F, L, A]] with XorTSemigroup[F, L, A] {
implicit val F0: Monoid[F[L Xor A]]
def empty: XorT[F, L, A] = XorT(F0.empty)
}

private[data] trait XorTSemigroupK[F[_], L] extends SemigroupK[XorT[F, L, ?]] {
implicit val F: Monad[F]
def combineK[A](x: XorT[F,L,A], y: XorT[F, L, A]): XorT[F, L, A] =
XorT(F.flatMap(x.value) {
case l @ Xor.Left(_) => y.value
case r @ Xor.Right(_) => F.pure(r)
})
}

private[data] trait XorTFunctor[F[_], L] extends Functor[XorT[F, L, ?]] {
@@ -316,8 +332,9 @@ private[data] trait XorTFunctor[F[_], L] extends Functor[XorT[F, L, ?]] {

private[data] trait XorTMonad[F[_], L] extends Monad[XorT[F, L, ?]] with XorTFunctor[F, L] {
implicit val F: Monad[F]
def pure[A](a: A): XorT[F, L, A] = XorT.pure[F, L, A](a)
def pure[A](a: A): XorT[F, L, A] = XorT(F.pure(Xor.right(a)))
def flatMap[A, B](fa: XorT[F, L, A])(f: A => XorT[F, L, B]): XorT[F, L, B] = fa flatMap f
override def ap[A, B](x: XorT[F, L, A => B])(y: XorT[F, L, A]): XorT[F, L, B] = super.ap(x)(y)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to override this if we are just calling through to super?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good spot - this is a left over from the conflicting Applicative.

}

private[data] trait XorTMonadError[F[_], L] extends MonadError[XorT[F, L, ?], L] with XorTMonad[F, L] {
30 changes: 25 additions & 5 deletions tests/src/test/scala/cats/tests/ListWrapper.scala
Original file line number Diff line number Diff line change
@@ -44,14 +44,21 @@ object ListWrapper {

def eqv[A : Eq]: Eq[ListWrapper[A]] = Eq[List[A]].on[ListWrapper[A]](_.list)

val foldable: Foldable[ListWrapper] =
new Foldable[ListWrapper] {
def foldLeft[A, B](fa: ListWrapper[A], b: B)(f: (B, A) => B): B =
Foldable[List].foldLeft(fa.list, b)(f)
val traverse: Traverse[ListWrapper] = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately I think there are going to be merge conflicts between this and #1103. I guess we'll have to get that sorted out after one of them is merged.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#1103 is merged - should I resync this or would it tell me if there were conflicts?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm interesting. It looks like maybe there's no merge conflict because the code is exactly the same?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like I mentioned somewhere, I didn't reinvent the wheel and reused the ListWrapper instances @yilinwei wrote here. It's still interesting there is no merge conflict at all though.

val F = Traverse[List]

new Traverse[ListWrapper] {
def foldLeft[A, B](fa: ListWrapper[A], b: B)(f: (B, A) => B): B =
F.foldLeft(fa.list, b)(f)
def foldRight[A, B](fa: ListWrapper[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
Foldable[List].foldRight(fa.list, lb)(f)
F.foldRight(fa.list, lb)(f)
def traverse[G[_], A, B](fa: ListWrapper[A])(f: A => G[B])(implicit G0: Applicative[G]): G[ListWrapper[B]] = {
G0.map(F.traverse(fa.list)(f))(ListWrapper.apply)
}
}
}

val foldable: Foldable[ListWrapper] = traverse

val functor: Functor[ListWrapper] =
new Functor[ListWrapper] {
@@ -85,6 +92,19 @@ object ListWrapper {
}
}

val monadRec: MonadRec[ListWrapper] = {
val M = MonadRec[List]

new MonadRec[ListWrapper] {
def pure[A](x: A): ListWrapper[A] = ListWrapper(M.pure(x))
def flatMap[A, B](fa: ListWrapper[A])(f: A => ListWrapper[B]): ListWrapper[B] = ListWrapper(M.flatMap(fa.list)(a => f(a).list))
def tailRecM[A, B](a: A)(f: A => ListWrapper[cats.data.Xor[A,B]]): ListWrapper[B] =
ListWrapper(M.tailRecM(a)(a => f(a).list))
}
}

val flatMapRec: FlatMapRec[ListWrapper] = monadRec

val monad: Monad[ListWrapper] = monadCombine

val applicative: Applicative[ListWrapper] = monadCombine
103 changes: 78 additions & 25 deletions tests/src/test/scala/cats/tests/XorTTests.scala
Original file line number Diff line number Diff line change
@@ -5,55 +5,108 @@ import cats.functor.Bifunctor
import cats.data.{Xor, XorT}
import cats.laws.discipline._
import cats.laws.discipline.arbitrary._
import cats.kernel.laws.OrderLaws
import cats.kernel.laws.{OrderLaws, GroupLaws}

class XorTTests extends CatsSuite {
implicit val eq0 = XorT.catsDataEqForXorT[List, String, String Xor Int]
implicit val eq1 = XorT.catsDataEqForXorT[XorT[List, String, ?], String, Int](eq0)
implicit val iso = CartesianTests.Isomorphisms.invariant[XorT[List, String, ?]]
checkAll("XorT[List, String, Int]", MonadErrorTests[XorT[List, String, ?], String].monadError[Int, Int, Int])
checkAll("MonadError[XorT[List, ?, ?]]", SerializableTests.serializable(MonadError[XorT[List, String, ?], String]))
checkAll("XorT[List, String, Int]", MonadRecTests[XorT[List, String, ?]].monadRec[Int, Int, Int])
checkAll("MonadRec[XorT[List, String, ?]]", SerializableTests.serializable(MonadRec[XorT[List, String, ?]]))
checkAll("XorT[List, ?, ?]", BifunctorTests[XorT[List, ?, ?]].bifunctor[Int, Int, Int, String, String, String])
checkAll("Bifunctor[XorT[List, ?, ?]]", SerializableTests.serializable(Bifunctor[XorT[List, ?, ?]]))
checkAll("XorT[List, ?, ?]", BitraverseTests[XorT[List, ?, ?]].bitraverse[Option, Int, Int, Int, String, String, String])
checkAll("Bitraverse[XorT[List, ?, ?]]", SerializableTests.serializable(Bitraverse[XorT[List, ?, ?]]))
checkAll("XorT[List, Int, ?]", TraverseTests[XorT[List, Int, ?]].traverse[Int, Int, Int, Int, Option, Option])
checkAll("Traverse[XorT[List, Int, ?]]", SerializableTests.serializable(Traverse[XorT[List, Int, ?]]))
checkAll("XorT[List, String, Int]", OrderLaws[XorT[List, String, Int]].order)
checkAll("Order[XorT[List, String, Int]]", SerializableTests.serializable(Order[XorT[List, String, Int]]))
checkAll("XorT[Option, ListWrapper[String], ?]", SemigroupKTests[XorT[Option, ListWrapper[String], ?]].semigroupK[Int])
checkAll("SemigroupK[XorT[Option, ListWrapper[String], ?]]", SerializableTests.serializable(SemigroupK[XorT[Option, ListWrapper[String], ?]]))
implicit val iso = CartesianTests.Isomorphisms.invariant[XorT[ListWrapper, String, ?]](XorT.catsDataFunctorForXorT(ListWrapper.functor))

{
implicit val F = ListWrapper.foldable
checkAll("XorT[ListWrapper, Int, ?]", FoldableTests[XorT[ListWrapper, Int, ?]].foldable[Int, Int])
checkAll("Foldable[XorT[ListWrapper, Int, ?]]", SerializableTests.serializable(Foldable[XorT[ListWrapper, Int, ?]]))
checkAll("XorT[Option, ListWrapper[String], ?]", SemigroupKTests[XorT[Option, ListWrapper[String], ?]].semigroupK[Int])
checkAll("SemigroupK[XorT[Option, ListWrapper[String], ?]]", SerializableTests.serializable(SemigroupK[XorT[Option, ListWrapper[String], ?]]))
}

{
implicit val F = ListWrapper.order[String Xor Int]

checkAll("XorT[List, String, Int]", OrderLaws[XorT[ListWrapper, String, Int]].order)
checkAll("Order[XorT[List, String, Int]]", SerializableTests.serializable(Order[XorT[ListWrapper, String, Int]]))
}

{
//If a Functor for F is defined
implicit val F = ListWrapper.functor

checkAll("XorT[ListWrapper, ?, ?]", BifunctorTests[XorT[ListWrapper, ?, ?]].bifunctor[Int, Int, Int, String, String, String])
checkAll("Bifunctor[XorT[ListWrapper, ?, ?]]", SerializableTests.serializable(Bifunctor[XorT[ListWrapper, ?, ?]]))
checkAll("XorT[ListWrapper, Int, ?]", FunctorTests[XorT[ListWrapper, Int, ?]].functor[Int, Int, Int])
checkAll("Functor[XorT[ListWrapper, Int, ?]]", SerializableTests.serializable(Functor[XorT[ListWrapper, Int, ?]]))
}

{
//If a Traverse for F is defined
implicit val F = ListWrapper.traverse

checkAll("XorT[ListWrapper, Int, ?]", TraverseTests[XorT[ListWrapper, Int, ?]].traverse[Int, Int, Int, Int, Option, Option])
checkAll("Traverse[XorT[ListWrapper, Int, ?]]", SerializableTests.serializable(Traverse[XorT[ListWrapper, Int, ?]]))
checkAll("XorT[ListWrapper, ?, ?]", BitraverseTests[XorT[ListWrapper, ?, ?]].bitraverse[Option, Int, Int, Int, String, String, String])
checkAll("Bitraverse[XorT[ListWrapper, ?, ?]]", SerializableTests.serializable(Bitraverse[XorT[ListWrapper, ?, ?]]))

}

{
//if a Monad is defined
implicit val F = ListWrapper.monad
implicit val eq0 = XorT.catsDataEqForXorT[ListWrapper, String, String Xor Int]
implicit val eq1 = XorT.catsDataEqForXorT[XorT[ListWrapper, String, ?], String, Int](eq0)

Functor[XorT[ListWrapper, String, ?]]
Applicative[XorT[ListWrapper, String, ?]]
Monad[XorT[ListWrapper, String, ?]]

checkAll("XorT[ListWrapper, String, Int]", MonadErrorTests[XorT[ListWrapper, String, ?], String].monadError[Int, Int, Int])
checkAll("MonadError[XorT[List, ?, ?]]", SerializableTests.serializable(MonadError[XorT[ListWrapper, String, ?], String]))
}

{
//if a MonadRec is defined
implicit val F = ListWrapper.monadRec

Functor[XorT[ListWrapper, String, ?]]
Applicative[XorT[ListWrapper, String, ?]]
Monad[XorT[ListWrapper, String, ?]]

checkAll("XorT[ListWrapper, String, Int]", MonadRecTests[XorT[ListWrapper, String, ?]].monadRec[Int, Int, Int])
checkAll("MonadRec[XorT[ListWrapper, String, ?]]", SerializableTests.serializable(MonadRec[XorT[ListWrapper, String, ?]]))
}

{
//If a foldable is defined
implicit val F = ListWrapper.foldable

checkAll("XorT[ListWrapper, Int, ?]", FoldableTests[XorT[ListWrapper, Int, ?]].foldable[Int, Int])
checkAll("Foldable[XorT[ListWrapper, Int, ?]]", SerializableTests.serializable(Foldable[XorT[ListWrapper, Int, ?]]))
}

{
implicit val F = ListWrapper.partialOrder[String Xor Int]

checkAll("XorT[ListWrapper, String, Int]", OrderLaws[XorT[ListWrapper, String, Int]].partialOrder)
checkAll("PartialOrder[XorT[ListWrapper, String, Int]]", SerializableTests.serializable(PartialOrder[XorT[ListWrapper, String, Int]]))
}

{
implicit val F = ListWrapper.semigroup[String Xor Int]

checkAll("XorT[ListWrapper, String, Int]", GroupLaws[XorT[ListWrapper, String, Int]].semigroup)
checkAll("Semigroup[XorT[ListWrapper, String, Int]]", SerializableTests.serializable(Semigroup[XorT[ListWrapper, String, Int]]))
}

{
implicit val F = ListWrapper.monoid[String Xor Int]

Semigroup[XorT[ListWrapper, String, Int]]

checkAll("XorT[ListWrapper, String, Int]", GroupLaws[XorT[ListWrapper, String, Int]].monoid)
checkAll("Monoid[XorT[ListWrapper, String, Int]]", SerializableTests.serializable(Monoid[XorT[ListWrapper, String, Int]]))
}

{
implicit val F = ListWrapper.eqv[String Xor Int]

checkAll("XorT[ListWrapper, String, Int]", OrderLaws[XorT[ListWrapper, String, Int]].eqv)
checkAll("Eq[XorT[ListWrapper, String, Int]]", SerializableTests.serializable(Eq[XorT[ListWrapper, String, Int]]))
}

// make sure that the Monad and Traverse instances don't result in ambiguous
// Functor instances
Functor[XorT[List, Int, ?]]

test("toValidated") {
forAll { (xort: XorT[List, String, Int]) =>
xort.toValidated.map(_.toXor) should === (xort.value)