From 9f16d2fa538b4a4978d4127b2a6e56e27ebe72f2 Mon Sep 17 00:00:00 2001 From: Denis Mikhaylov Date: Tue, 19 Jan 2016 00:04:33 +0300 Subject: [PATCH 1/4] Add Traverse instance for OneAnd --- core/src/main/scala/cats/data/OneAnd.scala | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/data/OneAnd.scala b/core/src/main/scala/cats/data/OneAnd.scala index 5500d15548..ab76417dae 100644 --- a/core/src/main/scala/cats/data/OneAnd.scala +++ b/core/src/main/scala/cats/data/OneAnd.scala @@ -87,7 +87,7 @@ final case class OneAnd[F[_], A](head: A, tail: F[A]) { s"OneAnd(${A.show(head)}, ${FA.show(tail)})" } -private[data] sealed trait OneAndInstances extends OneAndLowPriority1 { +private[data] sealed trait OneAndInstances extends OneAndLowPriority2 { implicit def oneAndEq[A, F[_]](implicit A: Eq[A], FA: Eq[F[A]]): Eq[OneAnd[F, A]] = new Eq[OneAnd[F, A]]{ @@ -163,4 +163,23 @@ trait OneAndLowPriority1 extends OneAndLowPriority0 { } } +trait OneAndLowPriority2 extends OneAndLowPriority1 { + implicit def oneAndTraverse[F[_]](implicit F: Traverse[F]): Traverse[OneAnd[F, ?]] = + new Traverse[OneAnd[F, ?]] { + def traverse[G[_], A, B](fa: OneAnd[F, A])(f: (A) => G[B])(implicit G: Applicative[G]): G[OneAnd[F, B]] = { + val tail = F.traverse(fa.tail)(f) + val head = f(fa.head) + G.ap2(head, tail)(G.pure(OneAnd(_, _))) + } + + def foldLeft[A, B](fa: OneAnd[F, A], b: B)(f: (B, A) => B): B = { + fa.foldLeft(b)(f) + } + + def foldRight[A, B](fa: OneAnd[F, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = { + fa.foldRight(lb)(f) + } + } +} + object OneAnd extends OneAndInstances From 72632023f800ee86f071449631b7b9371c34e058 Mon Sep 17 00:00:00 2001 From: Denis Mikhaylov Date: Tue, 19 Jan 2016 00:08:22 +0300 Subject: [PATCH 2/4] Add test for Traverse[OneAnd[F, ?]] --- tests/src/test/scala/cats/tests/OneAndTests.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/src/test/scala/cats/tests/OneAndTests.scala b/tests/src/test/scala/cats/tests/OneAndTests.scala index 0b6f5c3ea0..a60b16d23f 100644 --- a/tests/src/test/scala/cats/tests/OneAndTests.scala +++ b/tests/src/test/scala/cats/tests/OneAndTests.scala @@ -4,7 +4,7 @@ package tests import algebra.laws.{GroupLaws, OrderLaws} import cats.data.{NonEmptyList, OneAnd} -import cats.laws.discipline.{ComonadTests, FunctorTests, SemigroupKTests, FoldableTests, MonadTests, SerializableTests, MonoidalTests} +import cats.laws.discipline.{ComonadTests, FunctorTests, SemigroupKTests, FoldableTests, MonadTests, SerializableTests, MonoidalTests, TraverseTests} import cats.laws.discipline.arbitrary.{evalArbitrary, oneAndArbitrary} import cats.laws.discipline.eq._ @@ -13,6 +13,8 @@ import scala.util.Random class OneAndTests extends CatsSuite { checkAll("OneAnd[List, Int]", OrderLaws[OneAnd[List, Int]].eqv) + checkAll("OneAnd[List, Int] with Option", TraverseTests[OneAnd[List, ?]].traverse[Int, Int, Int, Int, Option, Option]) + implicit val iso = MonoidalTests.Isomorphisms.invariant[OneAnd[ListWrapper, ?]](OneAnd.oneAndFunctor(ListWrapper.functor)) // Test instances that have more general constraints From 49190b03e5024f60d965c530eb58865923b8c584 Mon Sep 17 00:00:00 2001 From: Denis Mikhaylov Date: Tue, 19 Jan 2016 00:28:10 +0300 Subject: [PATCH 3/4] Add serializability test for Traverse[OneAnd[F, ?]] --- tests/src/test/scala/cats/tests/OneAndTests.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/src/test/scala/cats/tests/OneAndTests.scala b/tests/src/test/scala/cats/tests/OneAndTests.scala index a60b16d23f..d9ae8796d0 100644 --- a/tests/src/test/scala/cats/tests/OneAndTests.scala +++ b/tests/src/test/scala/cats/tests/OneAndTests.scala @@ -14,6 +14,7 @@ class OneAndTests extends CatsSuite { checkAll("OneAnd[List, Int]", OrderLaws[OneAnd[List, Int]].eqv) checkAll("OneAnd[List, Int] with Option", TraverseTests[OneAnd[List, ?]].traverse[Int, Int, Int, Int, Option, Option]) + checkAll("Functor[OneAnd[List, A]]", SerializableTests.serializable(Traverse[OneAnd[List, ?]])) implicit val iso = MonoidalTests.Isomorphisms.invariant[OneAnd[ListWrapper, ?]](OneAnd.oneAndFunctor(ListWrapper.functor)) From 96e92b955d0f454e966f34718ab5ea1b1be5ab38 Mon Sep 17 00:00:00 2001 From: Denis Mikhaylov Date: Tue, 19 Jan 2016 09:25:46 +0300 Subject: [PATCH 4/4] Fix test name --- tests/src/test/scala/cats/tests/OneAndTests.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/test/scala/cats/tests/OneAndTests.scala b/tests/src/test/scala/cats/tests/OneAndTests.scala index d9ae8796d0..6728f9440f 100644 --- a/tests/src/test/scala/cats/tests/OneAndTests.scala +++ b/tests/src/test/scala/cats/tests/OneAndTests.scala @@ -14,7 +14,7 @@ class OneAndTests extends CatsSuite { checkAll("OneAnd[List, Int]", OrderLaws[OneAnd[List, Int]].eqv) checkAll("OneAnd[List, Int] with Option", TraverseTests[OneAnd[List, ?]].traverse[Int, Int, Int, Int, Option, Option]) - checkAll("Functor[OneAnd[List, A]]", SerializableTests.serializable(Traverse[OneAnd[List, ?]])) + checkAll("Traverse[OneAnd[List, A]]", SerializableTests.serializable(Traverse[OneAnd[List, ?]])) implicit val iso = MonoidalTests.Isomorphisms.invariant[OneAnd[ListWrapper, ?]](OneAnd.oneAndFunctor(ListWrapper.functor))