From 3679f006e6a2ea4125ebf6c566828fae9965883a Mon Sep 17 00:00:00 2001 From: Pere Villega Date: Tue, 16 Feb 2016 20:36:55 +0000 Subject: [PATCH 1/5] Add map method to OneAnd. Fix for #885 OneAnd was missing an instance of map. This commit tries to solve this. --- core/src/main/scala/cats/data/OneAnd.scala | 6 ++++++ tests/src/test/scala/cats/tests/OneAndTests.scala | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/core/src/main/scala/cats/data/OneAnd.scala b/core/src/main/scala/cats/data/OneAnd.scala index 5d4f89ad1e..98896b402e 100644 --- a/core/src/main/scala/cats/data/OneAnd.scala +++ b/core/src/main/scala/cats/data/OneAnd.scala @@ -65,6 +65,12 @@ final case class OneAnd[F[_], A](head: A, tail: F[A]) { def foldRight[B](lb: Eval[B])(f: (A, Eval[B]) => Eval[B])(implicit F: Foldable[F]): Eval[B] = Eval.defer(f(head, F.foldRight(tail, lb)(f))) + /** + * Applies f to all the elements of the structure + */ + def map[B](f: A => B)(implicit F: Functor[F]): OneAnd[F, B] = + OneAnd(f(head), F.map(tail)(f)) + /** * Typesafe equality operator. * diff --git a/tests/src/test/scala/cats/tests/OneAndTests.scala b/tests/src/test/scala/cats/tests/OneAndTests.scala index 8052c0424d..d6081b3cde 100644 --- a/tests/src/test/scala/cats/tests/OneAndTests.scala +++ b/tests/src/test/scala/cats/tests/OneAndTests.scala @@ -109,4 +109,11 @@ class OneAndTests extends CatsSuite { nel.forall(p) should === (list.forall(p)) } } + + test("NonEmptyList#map is consistent with List#map") { + forAll { (nel: NonEmptyList[Int], p: Int => String) => + val list = nel.unwrap + nel.map(p).unwrap should === (list.map(p)) + } + } } From b358cd267328eeb72a2b06a5531d866f446e507e Mon Sep 17 00:00:00 2001 From: Pere Villega Date: Tue, 16 Feb 2016 22:34:45 +0000 Subject: [PATCH 2/5] Replace the existing map definitions in the type class instances with the new map CoMonad required a explicit Functor[List], there may be a better alternative --- core/src/main/scala/cats/data/OneAnd.scala | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala/cats/data/OneAnd.scala b/core/src/main/scala/cats/data/OneAnd.scala index 98896b402e..a57c9f8507 100644 --- a/core/src/main/scala/cats/data/OneAnd.scala +++ b/core/src/main/scala/cats/data/OneAnd.scala @@ -120,7 +120,7 @@ private[data] sealed trait OneAndInstances extends OneAndLowPriority2 { implicit def oneAndMonad[F[_]](implicit monad: MonadCombine[F]): Monad[OneAnd[F, ?]] = new Monad[OneAnd[F, ?]] { override def map[A, B](fa: OneAnd[F, A])(f: A => B): OneAnd[F, B] = - OneAnd(f(fa.head), monad.map(fa.tail)(f)) + fa map f def pure[A](x: A): OneAnd[F, A] = OneAnd(x, monad.empty) @@ -139,6 +139,11 @@ private[data] sealed trait OneAndInstances extends OneAndLowPriority2 { trait OneAndLowPriority0 { implicit val nelComonad: Comonad[OneAnd[List, ?]] = new Comonad[OneAnd[List, ?]] { + val functorList: Functor[List] = + new Functor[List] { + def map[A, B](fa: List[A])(f: A => B): List[B] = + fa map f + } def coflatMap[A, B](fa: OneAnd[List, A])(f: OneAnd[List, A] => B): OneAnd[List, B] = { @tailrec def consume(as: List[A], buf: ListBuffer[B]): List[B] = @@ -153,7 +158,7 @@ trait OneAndLowPriority0 { fa.head def map[A, B](fa: OneAnd[List, A])(f: A => B): OneAnd[List, B] = - OneAnd(f(fa.head), fa.tail.map(f)) + fa.map(f)(functorList) } } @@ -161,7 +166,7 @@ trait OneAndLowPriority1 extends OneAndLowPriority0 { implicit def oneAndFunctor[F[_]](implicit F: Functor[F]): Functor[OneAnd[F, ?]] = new Functor[OneAnd[F, ?]] { def map[A, B](fa: OneAnd[F, A])(f: A => B): OneAnd[F, B] = - OneAnd(f(fa.head), F.map(fa.tail)(f)) + fa map f } } From 224486287d6141a1bc4921bd26c76a6403396119 Mon Sep 17 00:00:00 2001 From: Pere Villega Date: Tue, 16 Feb 2016 22:51:57 +0000 Subject: [PATCH 3/5] Replace Functor by existing Cats definition of Functor Import at trait level due to conflict with Semigroup definitions --- core/src/main/scala/cats/data/OneAnd.scala | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/core/src/main/scala/cats/data/OneAnd.scala b/core/src/main/scala/cats/data/OneAnd.scala index a57c9f8507..1c04bd404c 100644 --- a/core/src/main/scala/cats/data/OneAnd.scala +++ b/core/src/main/scala/cats/data/OneAnd.scala @@ -137,14 +137,10 @@ private[data] sealed trait OneAndInstances extends OneAndLowPriority2 { } trait OneAndLowPriority0 { + import cats.std.list._ + implicit val nelComonad: Comonad[OneAnd[List, ?]] = new Comonad[OneAnd[List, ?]] { - val functorList: Functor[List] = - new Functor[List] { - def map[A, B](fa: List[A])(f: A => B): List[B] = - fa map f - } - def coflatMap[A, B](fa: OneAnd[List, A])(f: OneAnd[List, A] => B): OneAnd[List, B] = { @tailrec def consume(as: List[A], buf: ListBuffer[B]): List[B] = as match { @@ -158,7 +154,7 @@ trait OneAndLowPriority0 { fa.head def map[A, B](fa: OneAnd[List, A])(f: A => B): OneAnd[List, B] = - fa.map(f)(functorList) + fa map f } } From 579fb2f3ef5c76c7901669530656b9693a09ceaa Mon Sep 17 00:00:00 2001 From: Pere Villega Date: Wed, 17 Feb 2016 10:12:15 +0000 Subject: [PATCH 4/5] Move import to the top and fix compilation issue Thanks @julien-truffaut for his help fixing this compilation error! --- core/src/main/scala/cats/data/OneAnd.scala | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala/cats/data/OneAnd.scala b/core/src/main/scala/cats/data/OneAnd.scala index 1c04bd404c..71106ceb90 100644 --- a/core/src/main/scala/cats/data/OneAnd.scala +++ b/core/src/main/scala/cats/data/OneAnd.scala @@ -3,6 +3,7 @@ package data import scala.annotation.tailrec import scala.collection.mutable.ListBuffer +import cats.std.list._ /** * A data type which represents a single element (head) and some other @@ -110,7 +111,7 @@ private[data] sealed trait OneAndInstances extends OneAndLowPriority2 { } implicit def oneAndSemigroup[F[_]: MonadCombine, A]: Semigroup[OneAnd[F, A]] = - oneAndSemigroupK.algebra + oneAndSemigroupK(MonadCombine[F]).algebra implicit def oneAndReducible[F[_]](implicit F: Foldable[F]): Reducible[OneAnd[F, ?]] = new NonEmptyReducible[OneAnd[F,?], F] { @@ -137,8 +138,6 @@ private[data] sealed trait OneAndInstances extends OneAndLowPriority2 { } trait OneAndLowPriority0 { - import cats.std.list._ - implicit val nelComonad: Comonad[OneAnd[List, ?]] = new Comonad[OneAnd[List, ?]] { def coflatMap[A, B](fa: OneAnd[List, A])(f: OneAnd[List, A] => B): OneAnd[List, B] = { From 5e26a015b3a26b1a396b9c4ea19537231f725a71 Mon Sep 17 00:00:00 2001 From: Pere Villega Date: Wed, 17 Feb 2016 14:51:17 +0000 Subject: [PATCH 5/5] Modify syntax as requested in PR comment --- core/src/main/scala/cats/data/OneAnd.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/data/OneAnd.scala b/core/src/main/scala/cats/data/OneAnd.scala index 71106ceb90..7bafd5ca76 100644 --- a/core/src/main/scala/cats/data/OneAnd.scala +++ b/core/src/main/scala/cats/data/OneAnd.scala @@ -111,7 +111,7 @@ private[data] sealed trait OneAndInstances extends OneAndLowPriority2 { } implicit def oneAndSemigroup[F[_]: MonadCombine, A]: Semigroup[OneAnd[F, A]] = - oneAndSemigroupK(MonadCombine[F]).algebra + oneAndSemigroupK[F].algebra implicit def oneAndReducible[F[_]](implicit F: Foldable[F]): Reducible[OneAnd[F, ?]] = new NonEmptyReducible[OneAnd[F,?], F] {