diff --git a/core/src/main/scala/cats/data/OneAnd.scala b/core/src/main/scala/cats/data/OneAnd.scala index 5d4f89ad1e..7bafd5ca76 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 @@ -65,6 +66,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. * @@ -104,7 +111,7 @@ private[data] sealed trait OneAndInstances extends OneAndLowPriority2 { } implicit def oneAndSemigroup[F[_]: MonadCombine, A]: Semigroup[OneAnd[F, A]] = - oneAndSemigroupK.algebra + oneAndSemigroupK[F].algebra implicit def oneAndReducible[F[_]](implicit F: Foldable[F]): Reducible[OneAnd[F, ?]] = new NonEmptyReducible[OneAnd[F,?], F] { @@ -114,7 +121,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) @@ -133,7 +140,6 @@ private[data] sealed trait OneAndInstances extends OneAndLowPriority2 { trait OneAndLowPriority0 { 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] = { @tailrec def consume(as: List[A], buf: ListBuffer[B]): List[B] = as match { @@ -147,7 +153,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 } } @@ -155,7 +161,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 } } 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)) + } + } }