From 2a0f012631f905dac6fa6ceb3d7bf878d6b06822 Mon Sep 17 00:00:00 2001 From: Cody Allen Date: Wed, 9 Sep 2015 20:51:20 -0400 Subject: [PATCH] Add toNel syntax to List --- core/src/main/scala/cats/data/package.scala | 6 ++++++ core/src/main/scala/cats/syntax/all.scala | 1 + core/src/main/scala/cats/syntax/list.scala | 12 ++++++++++++ .../scala/cats/laws/discipline/Arbitrary.scala | 4 ++-- .../src/test/scala/cats/tests/ListTests.scala | 15 ++++++++++++++- 5 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 core/src/main/scala/cats/syntax/list.scala diff --git a/core/src/main/scala/cats/data/package.scala b/core/src/main/scala/cats/data/package.scala index 8af74271c7..d35561465b 100644 --- a/core/src/main/scala/cats/data/package.scala +++ b/core/src/main/scala/cats/data/package.scala @@ -26,6 +26,12 @@ package object data { F.reduceRightTo(fa)(a => NonEmptyList(a, Nil)) { (a, lnel) => lnel.map { case OneAnd(h, t) => OneAnd(a, h :: t) } } + + def fromList[A](la: List[A]): Option[NonEmptyList[A]] = + la match { + case (h :: t) => Some(OneAnd(h, t)) + case Nil => None + } } type ReaderT[F[_], A, B] = Kleisli[F, A, B] diff --git a/core/src/main/scala/cats/syntax/all.scala b/core/src/main/scala/cats/syntax/all.scala index 433e696536..08ba6c48cf 100644 --- a/core/src/main/scala/cats/syntax/all.scala +++ b/core/src/main/scala/cats/syntax/all.scala @@ -15,6 +15,7 @@ trait AllSyntax with FunctorSyntax with GroupSyntax with InvariantSyntax + with ListSyntax with MonadCombineSyntax with MonadFilterSyntax with OptionSyntax diff --git a/core/src/main/scala/cats/syntax/list.scala b/core/src/main/scala/cats/syntax/list.scala new file mode 100644 index 0000000000..a7380318ec --- /dev/null +++ b/core/src/main/scala/cats/syntax/list.scala @@ -0,0 +1,12 @@ +package cats +package syntax + +import cats.data.NonEmptyList + +trait ListSyntax { + implicit def listSyntax[A](la: List[A]): ListOps[A] = new ListOps(la) +} + +final class ListOps[A](val la: List[A]) extends AnyVal { + def toNel: Option[NonEmptyList[A]] = NonEmptyList.fromList(la) +} diff --git a/laws/shared/src/main/scala/cats/laws/discipline/Arbitrary.scala b/laws/shared/src/main/scala/cats/laws/discipline/Arbitrary.scala index 7c34652db7..b3c93a533b 100644 --- a/laws/shared/src/main/scala/cats/laws/discipline/Arbitrary.scala +++ b/laws/shared/src/main/scala/cats/laws/discipline/Arbitrary.scala @@ -14,8 +14,8 @@ object arbitrary { implicit def constArbitrary[A, B](implicit A: Arbitrary[A]): Arbitrary[Const[A, B]] = Arbitrary(A.arbitrary.map(Const[A, B])) - implicit def oneAndArbitrary[F[_], A](implicit A: Arbitrary[A], F: ArbitraryK[F]): Arbitrary[OneAnd[A, F]] = - Arbitrary(F.synthesize[A].arbitrary.flatMap(fa => A.arbitrary.map(a => OneAnd(a, fa)))) + implicit def oneAndArbitrary[F[_], A](implicit A: Arbitrary[A], F: Arbitrary[F[A]]): Arbitrary[OneAnd[A, F]] = + Arbitrary(F.arbitrary.flatMap(fa => A.arbitrary.map(a => OneAnd(a, fa)))) implicit def xorArbitrary[A, B](implicit A: Arbitrary[A], B: Arbitrary[B]): Arbitrary[A Xor B] = Arbitrary(Gen.oneOf(A.arbitrary.map(Xor.left), B.arbitrary.map(Xor.right))) diff --git a/tests/shared/src/test/scala/cats/tests/ListTests.scala b/tests/shared/src/test/scala/cats/tests/ListTests.scala index 28901d2c48..9bbdbb37a5 100644 --- a/tests/shared/src/test/scala/cats/tests/ListTests.scala +++ b/tests/shared/src/test/scala/cats/tests/ListTests.scala @@ -1,9 +1,12 @@ package cats package tests +import cats.data.NonEmptyList import cats.laws.discipline.{TraverseTests, CoflatMapTests, MonadCombineTests, SerializableTests} +import cats.laws.discipline.arbitrary._ +import org.scalatest.prop.GeneratorDrivenPropertyChecks -class ListTests extends CatsSuite { +class ListTests extends CatsSuite with GeneratorDrivenPropertyChecks { checkAll("List[Int]", CoflatMapTests[List].coflatMap[Int, Int, Int]) checkAll("CoflatMap[List]", SerializableTests.serializable(CoflatMap[List])) @@ -12,4 +15,14 @@ class ListTests extends CatsSuite { checkAll("List[Int] with Option", TraverseTests[List].traverse[Int, Int, Int, Int, Option, Option]) checkAll("Traverse[List]", SerializableTests.serializable(Traverse[List])) + + test("nel => list => nel returns original nel")( + forAll { fa: NonEmptyList[Int] => + assert(fa.unwrap.toNel == Some(fa)) + } + ) + + test("toNel on empty list returns None"){ + assert(List.empty[Int].toNel == None) + } }