From 4edcd9edc778f55b53c8f659370c78637c48be48 Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Fri, 9 Aug 2019 06:47:34 -0500 Subject: [PATCH 01/17] Remove cats.instances.stream and introduce cats.kernel.instances.lazyList on 2.13 --- .../cats/instances/package.scala | 13 +++- .../scala-2.12-/cats/instances/stream.scala | 6 +- .../scala-2.13+/cats/instances/lazyList.scala | 25 ++++---- .../scala-2.13+/cats/instances/package.scala | 62 +++++++++++++++++++ core/src/main/scala/cats/data/OneAnd.scala | 4 +- core/src/main/scala/cats/data/ZipStream.scala | 7 ++- core/src/main/scala/cats/instances/all.scala | 1 + .../main/scala/cats/instances/parallel.scala | 2 +- .../cats/kernel/instances/AllInstances.scala | 0 .../kernel/instances/StreamInstances.scala | 56 +++++++++++++++++ .../kernel/instances/stream/package.scala | 0 .../cats/kernel/instances/AllInstances.scala | 36 +++++++++++ .../kernel/instances/LazyListInstances.scala} | 36 +++++------ .../kernel/instances/lazyList/package.scala | 4 ++ .../test/scala/cats/tests/FoldableSuite.scala | 4 +- 15 files changed, 212 insertions(+), 44 deletions(-) rename core/src/main/{scala => scala-2.12-}/cats/instances/package.scala (85%) create mode 100644 core/src/main/scala-2.13+/cats/instances/package.scala rename kernel/src/main/{scala => scala-2.12-}/cats/kernel/instances/AllInstances.scala (100%) create mode 100644 kernel/src/main/scala-2.12-/cats/kernel/instances/StreamInstances.scala rename kernel/src/main/{scala => scala-2.12-}/cats/kernel/instances/stream/package.scala (100%) create mode 100644 kernel/src/main/scala-2.13+/cats/kernel/instances/AllInstances.scala rename kernel/src/main/{scala/cats/kernel/instances/StreamInstances.scala => scala-2.13+/cats/kernel/instances/LazyListInstances.scala} (50%) create mode 100644 kernel/src/main/scala-2.13+/cats/kernel/instances/lazyList/package.scala diff --git a/core/src/main/scala/cats/instances/package.scala b/core/src/main/scala-2.12-/cats/instances/package.scala similarity index 85% rename from core/src/main/scala/cats/instances/package.scala rename to core/src/main/scala-2.12-/cats/instances/package.scala index bd880a9cb1..0104506020 100644 --- a/core/src/main/scala/cats/instances/package.scala +++ b/core/src/main/scala-2.12-/cats/instances/package.scala @@ -41,11 +41,22 @@ package object instances { object sortedMap extends SortedMapInstances with SortedMapInstancesBinCompat0 with SortedMapInstancesBinCompat1 object sortedSet extends SortedSetInstances with SortedSetInstancesBinCompat0 object stream extends StreamInstances with StreamInstancesBinCompat0 - object lazyList extends LazyListInstances object string extends StringInstances object try_ extends TryInstances object tuple extends TupleInstances with Tuple2InstancesBinCompat0 object unit extends UnitInstances object uuid extends UUIDInstances object vector extends VectorInstances with VectorInstancesBinCompat0 + + /** + * Used internally for avoiding version-specific code. + */ + private[cats] def crossVersionInstancesForLazyList: Monad[Stream] with Alternative[Stream] = + stream.catsStdInstancesForStream + + /** + * Used internally for avoiding version-specific code. + */ + private[cats] def crossVersionEqForLazyList[A: Eq]: Eq[Stream[A]] = + stream.catsKernelStdEqForStream[A] } diff --git a/core/src/main/scala-2.12-/cats/instances/stream.scala b/core/src/main/scala-2.12-/cats/instances/stream.scala index 83c4f9b18d..fea65002be 100644 --- a/core/src/main/scala-2.12-/cats/instances/stream.scala +++ b/core/src/main/scala-2.12-/cats/instances/stream.scala @@ -6,11 +6,9 @@ import cats.syntax.show._ import scala.annotation.tailrec /** - * For cross compile with backward compatibility + * Needed only to avoid some version-specific code in `cats.instances.all`. */ -trait LazyListInstances extends StreamInstances with StreamInstancesBinCompat0 { - val catsStdInstancesForLazyList = catsStdInstancesForStream -} +private[instances] trait LazyListInstances trait StreamInstances extends cats.kernel.instances.StreamInstances { diff --git a/core/src/main/scala-2.13+/cats/instances/lazyList.scala b/core/src/main/scala-2.13+/cats/instances/lazyList.scala index 0415d89a7b..e53371d594 100644 --- a/core/src/main/scala-2.13+/cats/instances/lazyList.scala +++ b/core/src/main/scala-2.13+/cats/instances/lazyList.scala @@ -5,15 +5,13 @@ import cats.syntax.show._ import scala.annotation.tailrec -//For cross compile with backward compatibility -trait StreamInstancesBinCompat0 +/** + * Needed only to avoid some version-specific code in `cats.instances.all`. + */ +private[instances] trait StreamInstances +private[instances] trait StreamInstancesBinCompat0 -//For cross compile with backward compatibility -trait StreamInstances extends LazyListInstances { - val catsStdInstancesForStream = catsStdInstancesForLazyList -} - -trait LazyListInstances extends cats.kernel.instances.StreamInstances { +trait LazyListInstances extends cats.kernel.instances.LazyListInstances { implicit val catsStdInstancesForLazyList : Traverse[LazyList] with Alternative[LazyList] with Monad[LazyList] with CoflatMap[LazyList] = new Traverse[LazyList] with Alternative[LazyList] with Monad[LazyList] with CoflatMap[LazyList] { @@ -71,10 +69,11 @@ trait LazyListInstances extends cats.kernel.instances.StreamInstances { def tailRecM[A, B](a: A)(fn: A => LazyList[Either[A, B]]): LazyList[B] = { val kernel = Iterator.unfold[Option[B], Iterator[Either[A, B]]](Iterator(Left(a))) { it => if (!it.hasNext) None - else it.next match { - case Left(a) => Some((None, fn(a).iterator ++ it)) - case Right(b) => Some((Some(b), it)) - } + else + it.next match { + case Left(a) => Some((None, fn(a).iterator ++ it)) + case Right(b) => Some((Some(b), it)) + } } LazyList.from(kernel.collect { case Some(v) => v }) } @@ -122,7 +121,7 @@ trait LazyListInstances extends cats.kernel.instances.StreamInstances { override def find[A](fa: LazyList[A])(f: A => Boolean): Option[A] = fa.find(f) - override def algebra[A]: Monoid[LazyList[A]] = new kernel.instances.StreamMonoid[A] + override def algebra[A]: Monoid[LazyList[A]] = new kernel.instances.LazyListMonoid[A] override def collectFirst[A, B](fa: LazyList[A])(pf: PartialFunction[A, B]): Option[B] = fa.collectFirst(pf) diff --git a/core/src/main/scala-2.13+/cats/instances/package.scala b/core/src/main/scala-2.13+/cats/instances/package.scala new file mode 100644 index 0000000000..694dd83d7e --- /dev/null +++ b/core/src/main/scala-2.13+/cats/instances/package.scala @@ -0,0 +1,62 @@ +package cats + +package object instances { + object all + extends AllInstances + with AllInstancesBinCompat0 + with AllInstancesBinCompat1 + with AllInstancesBinCompat2 + with AllInstancesBinCompat3 + with AllInstancesBinCompat4 + with AllInstancesBinCompat5 + object bigInt extends BigIntInstances + object bigDecimal extends BigDecimalInstances + object bitSet extends BitSetInstances + object boolean extends BooleanInstances + object byte extends ByteInstances + object char extends CharInstances + object double extends DoubleInstances + object duration extends CoreDurationInstances with DurationInstances + object either extends EitherInstances + object eq extends EqInstances + object equiv extends EquivInstances + object float extends FloatInstances + object finiteDuration extends CoreFiniteDurationInstances with FiniteDurationInstances + object function extends FunctionInstances with FunctionInstancesBinCompat0 + object future extends FutureInstances + object int extends IntInstances + object invariant extends InvariantMonoidalInstances + object list extends ListInstances with ListInstancesBinCompat0 + object long extends LongInstances + object option extends OptionInstances with OptionInstancesBinCompat0 + object map extends MapInstances with MapInstancesBinCompat0 with MapInstancesBinCompat1 + object order extends OrderInstances + object ordering extends OrderingInstances + object parallel extends ParallelInstances + object partialOrder extends PartialOrderInstances + object partialOrdering extends PartialOrderingInstances + object queue extends QueueInstances + object set extends SetInstances + object short extends ShortInstances + object sortedMap extends SortedMapInstances with SortedMapInstancesBinCompat0 with SortedMapInstancesBinCompat1 + object sortedSet extends SortedSetInstances with SortedSetInstancesBinCompat0 + object lazyList extends LazyListInstances + object string extends StringInstances + object try_ extends TryInstances + object tuple extends TupleInstances with Tuple2InstancesBinCompat0 + object unit extends UnitInstances + object uuid extends UUIDInstances + object vector extends VectorInstances with VectorInstancesBinCompat0 + + /** + * Used internally for avoiding version-specific code. + */ + private[cats] def crossVersionInstancesForLazyList: Monad[LazyList] with Alternative[LazyList] = + lazyList.catsStdInstancesForLazyList + + /** + * Used internally for avoiding version-specific code. + */ + private[cats] def crossVersionEqForLazyList[A: Eq]: Eq[LazyList[A]] = + lazyList.catsKernelStdEqForLazyList[A] +} diff --git a/core/src/main/scala/cats/data/OneAnd.scala b/core/src/main/scala/cats/data/OneAnd.scala index 755a417c26..92cfdde55e 100644 --- a/core/src/main/scala/cats/data/OneAnd.scala +++ b/core/src/main/scala/cats/data/OneAnd.scala @@ -3,7 +3,7 @@ package data import scala.annotation.tailrec import scala.collection.mutable.Builder -import cats.instances.stream._ +import cats.instances.crossVersionInstancesForLazyList import kernel.compat.scalaVersionSpecific._ /** @@ -209,7 +209,7 @@ sealed abstract private[data] class OneAndLowPriority4 { fa.head def map[A, B](fa: OneAnd[LazyList, A])(f: A => B): OneAnd[LazyList, B] = - fa.map(f) + fa.map(f)(crossVersionInstancesForLazyList) } } diff --git a/core/src/main/scala/cats/data/ZipStream.scala b/core/src/main/scala/cats/data/ZipStream.scala index d729434857..8813bc3a46 100644 --- a/core/src/main/scala/cats/data/ZipStream.scala +++ b/core/src/main/scala/cats/data/ZipStream.scala @@ -1,7 +1,7 @@ package cats package data -import instances.stream._ +import instances.{crossVersionEqForLazyList, crossVersionInstancesForLazyList} import kernel.compat.scalaVersionSpecific._ class ZipStream[A](val value: LazyList[A]) extends AnyVal @@ -27,8 +27,9 @@ object ZipStream { def empty[A]: ZipStream[A] = ZipStream(LazyList.empty[A]) def combineK[A](x: ZipStream[A], y: ZipStream[A]): ZipStream[A] = - ZipStream(Alternative[LazyList].combineK(x.value, y.value)) + ZipStream(crossVersionInstancesForLazyList.combineK(x.value, y.value)) } - implicit def catsDataEqForZipStream[A: Eq]: Eq[ZipStream[A]] = Eq.by(_.value) + implicit def catsDataEqForZipStream[A: Eq]: Eq[ZipStream[A]] = + Eq.by((_: ZipStream[A]).value)(crossVersionEqForLazyList[A]) } diff --git a/core/src/main/scala/cats/instances/all.scala b/core/src/main/scala/cats/instances/all.scala index ccc50d259b..69688235e0 100644 --- a/core/src/main/scala/cats/instances/all.scala +++ b/core/src/main/scala/cats/instances/all.scala @@ -13,6 +13,7 @@ trait AllInstances with FutureInstances with HashInstances with InvariantMonoidalInstances + with LazyListInstances with ListInstances with MapInstances with OptionInstances diff --git a/core/src/main/scala/cats/instances/parallel.scala b/core/src/main/scala/cats/instances/parallel.scala index 382c885300..213f0698d2 100644 --- a/core/src/main/scala/cats/instances/parallel.scala +++ b/core/src/main/scala/cats/instances/parallel.scala @@ -70,7 +70,7 @@ trait ParallelInstances extends ParallelInstances1 { implicit def catsStdParallelForZipStream[A]: Parallel[LazyList, ZipStream] = new Parallel[LazyList, ZipStream] { - def monad: Monad[LazyList] = cats.instances.stream.catsStdInstancesForStream + def monad: Monad[LazyList] = cats.instances.crossVersionInstancesForLazyList def applicative: Applicative[ZipStream] = ZipStream.catsDataAlternativeForZipStream def sequential: ZipStream ~> LazyList = diff --git a/kernel/src/main/scala/cats/kernel/instances/AllInstances.scala b/kernel/src/main/scala-2.12-/cats/kernel/instances/AllInstances.scala similarity index 100% rename from kernel/src/main/scala/cats/kernel/instances/AllInstances.scala rename to kernel/src/main/scala-2.12-/cats/kernel/instances/AllInstances.scala diff --git a/kernel/src/main/scala-2.12-/cats/kernel/instances/StreamInstances.scala b/kernel/src/main/scala-2.12-/cats/kernel/instances/StreamInstances.scala new file mode 100644 index 0000000000..c0e807b58b --- /dev/null +++ b/kernel/src/main/scala-2.12-/cats/kernel/instances/StreamInstances.scala @@ -0,0 +1,56 @@ +package cats.kernel +package instances +import compat.scalaVersionSpecific._ + +@suppressUnusedImportWarningForScalaVersionSpecific +trait StreamInstances extends StreamInstances1 { + implicit def catsKernelStdOrderForStream[A: Order]: Order[Stream[A]] = + new StreamOrder[A] + implicit def catsKernelStdMonoidForStream[A]: Monoid[Stream[A]] = + new StreamMonoid[A] +} + +trait StreamInstances1 extends StreamInstances2 { + implicit def catsKernelStdPartialOrderForStream[A: PartialOrder]: PartialOrder[Stream[A]] = + new StreamPartialOrder[A] + + implicit def catsKernelStdHashForStream[A: Hash]: Hash[Stream[A]] = + new StreamHash[A] +} + +trait StreamInstances2 { + implicit def catsKernelStdEqForStream[A: Eq]: Eq[Stream[A]] = + new StreamEq[A] +} + +class StreamOrder[A](implicit ev: Order[A]) extends Order[Stream[A]] { + def compare(xs: Stream[A], ys: Stream[A]): Int = + if (xs eq ys) 0 + else StaticMethods.iteratorCompare(xs.iterator, ys.iterator) +} + +class StreamPartialOrder[A](implicit ev: PartialOrder[A]) extends PartialOrder[Stream[A]] { + def partialCompare(xs: Stream[A], ys: Stream[A]): Double = + if (xs eq ys) 0.0 + else StaticMethods.iteratorPartialCompare(xs.iterator, ys.iterator) +} + +class StreamHash[A](implicit ev: Hash[A]) extends StreamEq[A]()(ev) with Hash[Stream[A]] { + def hash(xs: Stream[A]): Int = StaticMethods.orderedHash(xs) +} + +class StreamEq[A](implicit ev: Eq[A]) extends Eq[Stream[A]] { + def eqv(xs: Stream[A], ys: Stream[A]): Boolean = + if (xs eq ys) true + else StaticMethods.iteratorEq(xs.iterator, ys.iterator) +} + +class StreamMonoid[A] extends Monoid[Stream[A]] { + def empty: Stream[A] = Stream.empty + def combine(x: Stream[A], y: Stream[A]): Stream[A] = x ++ y + override def combineN(x: Stream[A], n: Int): Stream[A] = + StaticMethods.combineNIterable(Stream.newBuilder[A], x, n) + + override def combineAll(xs: IterableOnce[Stream[A]]): Stream[A] = + StaticMethods.combineAllIterable(Stream.newBuilder[A], xs) +} diff --git a/kernel/src/main/scala/cats/kernel/instances/stream/package.scala b/kernel/src/main/scala-2.12-/cats/kernel/instances/stream/package.scala similarity index 100% rename from kernel/src/main/scala/cats/kernel/instances/stream/package.scala rename to kernel/src/main/scala-2.12-/cats/kernel/instances/stream/package.scala diff --git a/kernel/src/main/scala-2.13+/cats/kernel/instances/AllInstances.scala b/kernel/src/main/scala-2.13+/cats/kernel/instances/AllInstances.scala new file mode 100644 index 0000000000..42ac2cfc90 --- /dev/null +++ b/kernel/src/main/scala-2.13+/cats/kernel/instances/AllInstances.scala @@ -0,0 +1,36 @@ +package cats.kernel +package instances + +trait AllInstances + extends BigDecimalInstances + with BigIntInstances + with BitSetInstances + with BooleanInstances + with ByteInstances + with CharInstances + with DoubleInstances + with EqInstances + with EitherInstances + with DurationInstances + with FloatInstances + with FunctionInstances + with HashInstances + with IntInstances + with LazyListInstances + with ListInstances + with LongInstances + with MapInstances + with OptionInstances + with OrderInstances + with PartialOrderInstances + with QueueInstances + with SetInstances + with ShortInstances + with StringInstances + with SymbolInstances + with TupleInstances + with UnitInstances + with UUIDInstances + with VectorInstances + +trait AllInstancesBinCompat0 extends FiniteDurationInstances diff --git a/kernel/src/main/scala/cats/kernel/instances/StreamInstances.scala b/kernel/src/main/scala-2.13+/cats/kernel/instances/LazyListInstances.scala similarity index 50% rename from kernel/src/main/scala/cats/kernel/instances/StreamInstances.scala rename to kernel/src/main/scala-2.13+/cats/kernel/instances/LazyListInstances.scala index e8efde0b10..c19d3ad5f7 100644 --- a/kernel/src/main/scala/cats/kernel/instances/StreamInstances.scala +++ b/kernel/src/main/scala-2.13+/cats/kernel/instances/LazyListInstances.scala @@ -3,49 +3,49 @@ package instances import compat.scalaVersionSpecific._ @suppressUnusedImportWarningForScalaVersionSpecific -trait StreamInstances extends StreamInstances1 { - implicit def catsKernelStdOrderForStream[A: Order]: Order[LazyList[A]] = - new StreamOrder[A] - implicit def catsKernelStdMonoidForStream[A]: Monoid[LazyList[A]] = - new StreamMonoid[A] +trait LazyListInstances extends LazyListInstances1 { + implicit def catsKernelStdOrderForLazyList[A: Order]: Order[LazyList[A]] = + new LazyListOrder[A] + implicit def catsKernelStdMonoidForLazyList[A]: Monoid[LazyList[A]] = + new LazyListMonoid[A] } -trait StreamInstances1 extends StreamInstances2 { - implicit def catsKernelStdPartialOrderForStream[A: PartialOrder]: PartialOrder[LazyList[A]] = - new StreamPartialOrder[A] +trait LazyListInstances1 extends LazyListInstances2 { + implicit def catsKernelStdPartialOrderForLazyList[A: PartialOrder]: PartialOrder[LazyList[A]] = + new LazyListPartialOrder[A] - implicit def catsKernelStdHashForStream[A: Hash]: Hash[LazyList[A]] = - new StreamHash[A] + implicit def catsKernelStdHashForLazyList[A: Hash]: Hash[LazyList[A]] = + new LazyListHash[A] } -trait StreamInstances2 { - implicit def catsKernelStdEqForStream[A: Eq]: Eq[LazyList[A]] = - new StreamEq[A] +trait LazyListInstances2 { + implicit def catsKernelStdEqForLazyList[A: Eq]: Eq[LazyList[A]] = + new LazyListEq[A] } -class StreamOrder[A](implicit ev: Order[A]) extends Order[LazyList[A]] { +class LazyListOrder[A](implicit ev: Order[A]) extends Order[LazyList[A]] { def compare(xs: LazyList[A], ys: LazyList[A]): Int = if (xs eq ys) 0 else StaticMethods.iteratorCompare(xs.iterator, ys.iterator) } -class StreamPartialOrder[A](implicit ev: PartialOrder[A]) extends PartialOrder[LazyList[A]] { +class LazyListPartialOrder[A](implicit ev: PartialOrder[A]) extends PartialOrder[LazyList[A]] { def partialCompare(xs: LazyList[A], ys: LazyList[A]): Double = if (xs eq ys) 0.0 else StaticMethods.iteratorPartialCompare(xs.iterator, ys.iterator) } -class StreamHash[A](implicit ev: Hash[A]) extends StreamEq[A]()(ev) with Hash[LazyList[A]] { +class LazyListHash[A](implicit ev: Hash[A]) extends LazyListEq[A]()(ev) with Hash[LazyList[A]] { def hash(xs: LazyList[A]): Int = StaticMethods.orderedHash(xs) } -class StreamEq[A](implicit ev: Eq[A]) extends Eq[LazyList[A]] { +class LazyListEq[A](implicit ev: Eq[A]) extends Eq[LazyList[A]] { def eqv(xs: LazyList[A], ys: LazyList[A]): Boolean = if (xs eq ys) true else StaticMethods.iteratorEq(xs.iterator, ys.iterator) } -class StreamMonoid[A] extends Monoid[LazyList[A]] { +class LazyListMonoid[A] extends Monoid[LazyList[A]] { def empty: LazyList[A] = LazyList.empty def combine(x: LazyList[A], y: LazyList[A]): LazyList[A] = x ++ y override def combineN(x: LazyList[A], n: Int): LazyList[A] = diff --git a/kernel/src/main/scala-2.13+/cats/kernel/instances/lazyList/package.scala b/kernel/src/main/scala-2.13+/cats/kernel/instances/lazyList/package.scala new file mode 100644 index 0000000000..b1709ca425 --- /dev/null +++ b/kernel/src/main/scala-2.13+/cats/kernel/instances/lazyList/package.scala @@ -0,0 +1,4 @@ +package cats.kernel +package instances + +package object lazyList extends LazyListInstances diff --git a/tests/src/test/scala/cats/tests/FoldableSuite.scala b/tests/src/test/scala/cats/tests/FoldableSuite.scala index 9325f9897e..18e195621b 100644 --- a/tests/src/test/scala/cats/tests/FoldableSuite.scala +++ b/tests/src/test/scala/cats/tests/FoldableSuite.scala @@ -404,10 +404,10 @@ class FoldableSuiteAdditional extends CatsSuite { def foldableLazyListWithDefaultImpl = new Foldable[LazyList] { def foldLeft[A, B](fa: LazyList[A], b: B)(f: (B, A) => B): B = - instances.lazyList.catsStdInstancesForLazyList.foldLeft(fa, b)(f) + Foldable[LazyList].foldLeft(fa, b)(f) def foldRight[A, B](fa: LazyList[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = - instances.lazyList.catsStdInstancesForLazyList.foldRight(fa, lb)(f) + Foldable[LazyList].foldRight(fa, lb)(f) } test(".foldLeftM short-circuiting") { From d843f04309a8f40d0447159f45bc1252a3f53c05 Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Mon, 19 Aug 2019 07:30:48 -0500 Subject: [PATCH 02/17] Reinstate stream instances on 2.13 --- .../scala-2.13+/cats/instances/lazyList.scala | 6 - .../scala-2.13+/cats/instances/package.scala | 1 + .../scala-2.13+/cats/instances/stream.scala | 191 ++++++++++++++++++ .../kernel/instances/StreamInstances.scala | 66 ++++++ .../kernel/instances/stream/package.scala | 0 5 files changed, 258 insertions(+), 6 deletions(-) create mode 100644 core/src/main/scala-2.13+/cats/instances/stream.scala create mode 100644 kernel/src/main/scala-2.13+/cats/kernel/instances/StreamInstances.scala rename kernel/src/main/{scala-2.12- => scala}/cats/kernel/instances/stream/package.scala (100%) diff --git a/core/src/main/scala-2.13+/cats/instances/lazyList.scala b/core/src/main/scala-2.13+/cats/instances/lazyList.scala index e53371d594..1d55cb8c21 100644 --- a/core/src/main/scala-2.13+/cats/instances/lazyList.scala +++ b/core/src/main/scala-2.13+/cats/instances/lazyList.scala @@ -5,12 +5,6 @@ import cats.syntax.show._ import scala.annotation.tailrec -/** - * Needed only to avoid some version-specific code in `cats.instances.all`. - */ -private[instances] trait StreamInstances -private[instances] trait StreamInstancesBinCompat0 - trait LazyListInstances extends cats.kernel.instances.LazyListInstances { implicit val catsStdInstancesForLazyList : Traverse[LazyList] with Alternative[LazyList] with Monad[LazyList] with CoflatMap[LazyList] = diff --git a/core/src/main/scala-2.13+/cats/instances/package.scala b/core/src/main/scala-2.13+/cats/instances/package.scala index 694dd83d7e..06796ef6db 100644 --- a/core/src/main/scala-2.13+/cats/instances/package.scala +++ b/core/src/main/scala-2.13+/cats/instances/package.scala @@ -40,6 +40,7 @@ package object instances { object short extends ShortInstances object sortedMap extends SortedMapInstances with SortedMapInstancesBinCompat0 with SortedMapInstancesBinCompat1 object sortedSet extends SortedSetInstances with SortedSetInstancesBinCompat0 + object stream extends StreamInstances with StreamInstancesBinCompat0 object lazyList extends LazyListInstances object string extends StringInstances object try_ extends TryInstances diff --git a/core/src/main/scala-2.13+/cats/instances/stream.scala b/core/src/main/scala-2.13+/cats/instances/stream.scala new file mode 100644 index 0000000000..29a6fd7e63 --- /dev/null +++ b/core/src/main/scala-2.13+/cats/instances/stream.scala @@ -0,0 +1,191 @@ +package cats +package instances + +import cats.syntax.show._ + +import scala.annotation.tailrec + +trait StreamInstances extends cats.kernel.instances.StreamInstances { + + @deprecated("2.0.0-RC2", "Use cats.instances.lazyList") + implicit val catsStdInstancesForStream + : Traverse[Stream] with Alternative[Stream] with Monad[Stream] with CoflatMap[Stream] = + new Traverse[Stream] with Alternative[Stream] with Monad[Stream] with CoflatMap[Stream] { + + def empty[A]: Stream[A] = Stream.Empty + + def combineK[A](x: Stream[A], y: Stream[A]): Stream[A] = x #::: y + + def pure[A](x: A): Stream[A] = Stream(x) + + override def map[A, B](fa: Stream[A])(f: A => B): Stream[B] = + fa.map(f) + + def flatMap[A, B](fa: Stream[A])(f: A => Stream[B]): Stream[B] = + fa.flatMap(f) + + override def map2[A, B, Z](fa: Stream[A], fb: Stream[B])(f: (A, B) => Z): Stream[Z] = + if (fb.isEmpty) Stream.empty // do O(1) work if fb is empty + else fa.flatMap(a => fb.map(b => f(a, b))) // already O(1) if fa is empty + + override def map2Eval[A, B, Z](fa: Stream[A], fb: Eval[Stream[B]])(f: (A, B) => Z): Eval[Stream[Z]] = + if (fa.isEmpty) Eval.now(Stream.empty) // no need to evaluate fb + else fb.map(fb => map2(fa, fb)(f)) + + def coflatMap[A, B](fa: Stream[A])(f: Stream[A] => B): Stream[B] = + fa.tails.toStream.init.map(f) + + def foldLeft[A, B](fa: Stream[A], b: B)(f: (B, A) => B): B = + fa.foldLeft(b)(f) + + def foldRight[A, B](fa: Stream[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + Now(fa).flatMap { s => + // Note that we don't use pattern matching to deconstruct the + // stream, since that would needlessly force the tail. + if (s.isEmpty) lb else f(s.head, Eval.defer(foldRight(s.tail, lb)(f))) + } + + override def foldMap[A, B](fa: Stream[A])(f: A => B)(implicit B: Monoid[B]): B = + B.combineAll(fa.iterator.map(f)) + + def traverse[G[_], A, B](fa: Stream[A])(f: A => G[B])(implicit G: Applicative[G]): G[Stream[B]] = + // We use foldRight to avoid possible stack overflows. Since + // we don't want to return a Eval[_] instance, we call .value + // at the end. + foldRight(fa, Always(G.pure(Stream.empty[B]))) { (a, lgsb) => + G.map2Eval(f(a), lgsb)(_ #:: _) + }.value + + override def mapWithIndex[A, B](fa: Stream[A])(f: (A, Int) => B): Stream[B] = + fa.zipWithIndex.map(ai => f(ai._1, ai._2)) + + override def zipWithIndex[A](fa: Stream[A]): Stream[(A, Int)] = + fa.zipWithIndex + + def tailRecM[A, B](a: A)(fn: A => Stream[Either[A, B]]): Stream[B] = { + val it: Iterator[B] = new Iterator[B] { + var stack: Stream[Either[A, B]] = fn(a) + var state: Either[Unit, Option[B]] = Left(()) + + @tailrec + def advance(): Unit = stack match { + case Right(b) #:: tail => + stack = tail + state = Right(Some(b)) + case Left(a) #:: tail => + stack = fn(a) #::: tail + advance() + case empty => + state = Right(None) + } + + @tailrec + def hasNext: Boolean = state match { + case Left(()) => + advance() + hasNext + case Right(o) => + o.isDefined + } + + @tailrec + def next(): B = state match { + case Left(()) => + advance() + next() + case Right(o) => + val b = o.get + advance() + b + } + } + + it.toStream + } + + override def exists[A](fa: Stream[A])(p: A => Boolean): Boolean = + fa.exists(p) + + override def forall[A](fa: Stream[A])(p: A => Boolean): Boolean = + fa.forall(p) + + override def get[A](fa: Stream[A])(idx: Long): Option[A] = { + @tailrec + def go(idx: Long, s: Stream[A]): Option[A] = + s match { + case h #:: tail => + if (idx == 0L) Some(h) else go(idx - 1L, tail) + case _ => None + } + if (idx < 0L) None else go(idx, fa) + } + + override def isEmpty[A](fa: Stream[A]): Boolean = fa.isEmpty + + override def foldM[G[_], A, B](fa: Stream[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] = { + def step(in: (Stream[A], B)): G[Either[(Stream[A], B), B]] = { + val (s, b) = in + if (s.isEmpty) + G.pure(Right(b)) + else + G.map(f(b, s.head)) { bnext => + Left((s.tail, bnext)) + } + } + + G.tailRecM((fa, z))(step) + } + + override def fold[A](fa: Stream[A])(implicit A: Monoid[A]): A = A.combineAll(fa) + + override def toList[A](fa: Stream[A]): List[A] = fa.toList + + override def reduceLeftOption[A](fa: Stream[A])(f: (A, A) => A): Option[A] = + fa.reduceLeftOption(f) + + override def find[A](fa: Stream[A])(f: A => Boolean): Option[A] = fa.find(f) + + override def algebra[A]: Monoid[Stream[A]] = new kernel.instances.StreamMonoid[A] + + override def collectFirst[A, B](fa: Stream[A])(pf: PartialFunction[A, B]): Option[B] = fa.collectFirst(pf) + + override def collectFirstSome[A, B](fa: Stream[A])(f: A => Option[B]): Option[B] = + fa.collectFirst(Function.unlift(f)) + } + + @deprecated("2.0.0-RC2", "Use cats.instances.lazyList") + implicit def catsStdShowForStream[A: Show]: Show[Stream[A]] = + new Show[Stream[A]] { + def show(fa: Stream[A]): String = if (fa.isEmpty) "Stream()" else s"Stream(${fa.head.show}, ?)" + } + +} + +trait StreamInstancesBinCompat0 { + @deprecated("2.0.0-RC2", "Use cats.instances.lazyList") + implicit val catsStdTraverseFilterForStream: TraverseFilter[Stream] = new TraverseFilter[Stream] { + val traverse: Traverse[Stream] = cats.instances.stream.catsStdInstancesForStream + + override def mapFilter[A, B](fa: Stream[A])(f: (A) => Option[B]): Stream[B] = + fa.collect(Function.unlift(f)) + + override def filter[A](fa: Stream[A])(f: (A) => Boolean): Stream[A] = fa.filter(f) + + override def collect[A, B](fa: Stream[A])(f: PartialFunction[A, B]): Stream[B] = fa.collect(f) + + override def flattenOption[A](fa: Stream[Option[A]]): Stream[A] = fa.flatten + + def traverseFilter[G[_], A, B](fa: Stream[A])(f: (A) => G[Option[B]])(implicit G: Applicative[G]): G[Stream[B]] = + fa.foldRight(Eval.now(G.pure(Stream.empty[B])))( + (x, xse) => G.map2Eval(f(x), xse)((i, o) => i.fold(o)(_ +: o)) + ) + .value + + override def filterA[G[_], A](fa: Stream[A])(f: (A) => G[Boolean])(implicit G: Applicative[G]): G[Stream[A]] = + fa.foldRight(Eval.now(G.pure(Stream.empty[A])))( + (x, xse) => G.map2Eval(f(x), xse)((b, as) => if (b) x +: as else as) + ) + .value + + } +} diff --git a/kernel/src/main/scala-2.13+/cats/kernel/instances/StreamInstances.scala b/kernel/src/main/scala-2.13+/cats/kernel/instances/StreamInstances.scala new file mode 100644 index 0000000000..80f02872bc --- /dev/null +++ b/kernel/src/main/scala-2.13+/cats/kernel/instances/StreamInstances.scala @@ -0,0 +1,66 @@ +package cats.kernel +package instances +import compat.scalaVersionSpecific._ + +@suppressUnusedImportWarningForScalaVersionSpecific +trait StreamInstances extends StreamInstances1 { + @deprecated("2.0.0-RC2", "Use cats.kernel.instances.lazyList") + implicit def catsKernelStdOrderForStream[A: Order]: Order[Stream[A]] = + new StreamOrder[A] + @deprecated("2.0.0-RC2", "Use cats.kernel.instances.lazyList") + implicit def catsKernelStdMonoidForStream[A]: Monoid[Stream[A]] = + new StreamMonoid[A] +} + +trait StreamInstances1 extends StreamInstances2 { + @deprecated("2.0.0-RC2", "Use cats.kernel.instances.lazyList") + implicit def catsKernelStdPartialOrderForStream[A: PartialOrder]: PartialOrder[Stream[A]] = + new StreamPartialOrder[A] + + @deprecated("2.0.0-RC2", "Use cats.kernel.instances.lazyList") + implicit def catsKernelStdHashForStream[A: Hash]: Hash[Stream[A]] = + new StreamHash[A] +} + +trait StreamInstances2 { + @deprecated("2.0.0-RC2", "Use cats.kernel.instances.lazyList") + implicit def catsKernelStdEqForStream[A: Eq]: Eq[Stream[A]] = + new StreamEq[A] +} + +@deprecated("2.0.0-RC2", "Use cats.kernel.instances.lazyList") +class StreamOrder[A](implicit ev: Order[A]) extends Order[Stream[A]] { + def compare(xs: Stream[A], ys: Stream[A]): Int = + if (xs eq ys) 0 + else StaticMethods.iteratorCompare(xs.iterator, ys.iterator) +} + +@deprecated("2.0.0-RC2", "Use cats.kernel.instances.lazyList") +class StreamPartialOrder[A](implicit ev: PartialOrder[A]) extends PartialOrder[Stream[A]] { + def partialCompare(xs: Stream[A], ys: Stream[A]): Double = + if (xs eq ys) 0.0 + else StaticMethods.iteratorPartialCompare(xs.iterator, ys.iterator) +} + +@deprecated("2.0.0-RC2", "Use cats.kernel.instances.lazyList") +class StreamHash[A](implicit ev: Hash[A]) extends StreamEq[A]()(ev) with Hash[Stream[A]] { + def hash(xs: Stream[A]): Int = StaticMethods.orderedHash(xs) +} + +@deprecated("2.0.0-RC2", "Use cats.kernel.instances.lazyList") +class StreamEq[A](implicit ev: Eq[A]) extends Eq[Stream[A]] { + def eqv(xs: Stream[A], ys: Stream[A]): Boolean = + if (xs eq ys) true + else StaticMethods.iteratorEq(xs.iterator, ys.iterator) +} + +@deprecated("2.0.0-RC2", "Use cats.kernel.instances.lazyList") +class StreamMonoid[A] extends Monoid[Stream[A]] { + def empty: Stream[A] = Stream.empty + def combine(x: Stream[A], y: Stream[A]): Stream[A] = x ++ y + override def combineN(x: Stream[A], n: Int): Stream[A] = + StaticMethods.combineNIterable(Stream.newBuilder[A], x, n) + + override def combineAll(xs: IterableOnce[Stream[A]]): Stream[A] = + StaticMethods.combineAllIterable(Stream.newBuilder[A], xs) +} diff --git a/kernel/src/main/scala-2.12-/cats/kernel/instances/stream/package.scala b/kernel/src/main/scala/cats/kernel/instances/stream/package.scala similarity index 100% rename from kernel/src/main/scala-2.12-/cats/kernel/instances/stream/package.scala rename to kernel/src/main/scala/cats/kernel/instances/stream/package.scala From 6f8658ba83421b5a76e0077334a0e93803b8ecb4 Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Mon, 19 Aug 2019 11:58:59 -0500 Subject: [PATCH 03/17] Don't alias LazyList to Stream pre-2.13 --- build.sbt | 1 + .../scala-2.12-/cats/compat/lazyList.scala | 9 -- .../cats/data/OneAndLowPriority4.scala | 26 ++++ .../data/ScalaVersionSpecificPackage.scala | 14 +- .../cats/data/ZipStream.scala | 13 +- ...calaVersionSpecificParallelInstances.scala | 110 ++++++++++++++ .../scala-2.12-/cats/instances/package.scala | 12 -- .../scala-2.13+/cats/compat/lazyList.scala | 7 - .../cats/data/NonEmptyLazyList.scala | 40 ++++- .../cats/data/OneAndLowPriority4.scala | 46 ++++++ .../data/ScalaVersionSpecificPackage.scala | 14 +- .../scala-2.13+/cats/data/ZipLazyList.scala | 31 ++++ .../scala-2.13+/cats/data/ZipStream.scala | 36 +++++ ...calaVersionSpecificParallelInstances.scala | 124 +++++++++++++++ .../scala-2.13+/cats/instances/package.scala | 14 +- .../main/scala/cats/data/NonEmptyVector.scala | 2 +- core/src/main/scala/cats/data/OneAnd.scala | 23 --- core/src/main/scala/cats/data/package.scala | 13 -- .../main/scala/cats/instances/parallel.scala | 105 +------------ .../main/scala/cats/instances/sortedSet.scala | 16 +- .../scala/cats/kernel/laws/LawTests.scala | 12 +- .../kernel/compat/scalaVersionSpecific.scala | 2 - .../cats/kernel/instances/AllInstances.scala | 1 + .../discipline/ScalaVersionSpecific.scala | 8 +- .../discipline/ScalaVersionSpecific.scala | 15 +- .../cats/laws/discipline/arbitrary.scala | 3 - .../cats/tests/ScalaVersionSpecific.scala | 6 + .../cats/tests/LazyListSuite.scala | 17 +-- .../cats/tests/ScalaVersionSpecific.scala | 142 ++++++++++++++++++ .../BinCodecInvariantMonoidalSuite.scala | 2 +- .../test/scala/cats/tests/FoldableSuite.scala | 55 ++++--- .../test/scala/cats/tests/ParallelSuite.scala | 32 +--- .../scala/cats/tests/RegressionSuite.scala | 4 +- .../test/scala/cats/tests/StreamSuite.scala | 61 ++++++++ .../test/scala/cats/tests/TraverseSuite.scala | 9 +- 35 files changed, 733 insertions(+), 292 deletions(-) delete mode 100644 core/src/main/scala-2.12-/cats/compat/lazyList.scala create mode 100644 core/src/main/scala-2.12-/cats/data/OneAndLowPriority4.scala rename core/src/main/{scala => scala-2.12-}/cats/data/ZipStream.scala (63%) create mode 100644 core/src/main/scala-2.12-/cats/instances/ScalaVersionSpecificParallelInstances.scala delete mode 100644 core/src/main/scala-2.13+/cats/compat/lazyList.scala create mode 100644 core/src/main/scala-2.13+/cats/data/OneAndLowPriority4.scala create mode 100644 core/src/main/scala-2.13+/cats/data/ZipLazyList.scala create mode 100644 core/src/main/scala-2.13+/cats/data/ZipStream.scala create mode 100644 core/src/main/scala-2.13+/cats/instances/ScalaVersionSpecificParallelInstances.scala create mode 100644 tests/src/test/scala-2.12-/cats/tests/ScalaVersionSpecific.scala rename tests/src/test/{scala => scala-2.13+}/cats/tests/LazyListSuite.scala (74%) create mode 100644 tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala create mode 100644 tests/src/test/scala/cats/tests/StreamSuite.scala diff --git a/build.sbt b/build.sbt index c26adbec6b..45a76efc40 100644 --- a/build.sbt +++ b/build.sbt @@ -523,6 +523,7 @@ lazy val kernelLaws = crossProject(JSPlatform, JVMPlatform) .settings(scoverageSettings) .settings(disciplineDependencies) .settings(testingDependencies) + .settings(scalacOptions in Test := (scalacOptions in Test).value.filter(_ != "-Xfatal-warnings")) .jsSettings(commonJsSettings) .jvmSettings(commonJvmSettings) .jsSettings(coverageEnabled := false) diff --git a/core/src/main/scala-2.12-/cats/compat/lazyList.scala b/core/src/main/scala-2.12-/cats/compat/lazyList.scala deleted file mode 100644 index 71b7a8131d..0000000000 --- a/core/src/main/scala-2.12-/cats/compat/lazyList.scala +++ /dev/null @@ -1,9 +0,0 @@ -package cats.compat - -object lazyList { - - def toLazyList[A](traversableOnce: TraversableOnce[A]): Stream[A] = traversableOnce.toStream - - def lazyListString: String = "Stream" - -} diff --git a/core/src/main/scala-2.12-/cats/data/OneAndLowPriority4.scala b/core/src/main/scala-2.12-/cats/data/OneAndLowPriority4.scala new file mode 100644 index 0000000000..084253818d --- /dev/null +++ b/core/src/main/scala-2.12-/cats/data/OneAndLowPriority4.scala @@ -0,0 +1,26 @@ +package cats +package data + +import scala.annotation.tailrec +import scala.collection.mutable.Builder + +abstract private[data] class OneAndLowPriority4 { + implicit val catsDataComonadForNonEmptyStream: Comonad[OneAnd[Stream, *]] = + new Comonad[OneAnd[Stream, *]] { + def coflatMap[A, B](fa: OneAnd[Stream, A])(f: OneAnd[Stream, A] => B): OneAnd[Stream, B] = { + @tailrec def consume(as: Stream[A], buf: Builder[B, Stream[B]]): Stream[B] = + if (as.isEmpty) buf.result + else { + val tail = as.tail + consume(tail, buf += f(OneAnd(as.head, tail))) + } + OneAnd(f(fa), consume(fa.tail, Stream.newBuilder)) + } + + def extract[A](fa: OneAnd[Stream, A]): A = + fa.head + + def map[A, B](fa: OneAnd[Stream, A])(f: A => B): OneAnd[Stream, B] = + fa.map(f)(cats.instances.stream.catsStdInstancesForStream) + } +} diff --git a/core/src/main/scala-2.12-/cats/data/ScalaVersionSpecificPackage.scala b/core/src/main/scala-2.12-/cats/data/ScalaVersionSpecificPackage.scala index 24a811e068..bc11af201a 100644 --- a/core/src/main/scala-2.12-/cats/data/ScalaVersionSpecificPackage.scala +++ b/core/src/main/scala-2.12-/cats/data/ScalaVersionSpecificPackage.scala @@ -1,5 +1,15 @@ package cats - package data -abstract private[data] class ScalaVersionSpecificPackage +import kernel.compat.scalaVersionSpecific._ + +abstract private[data] class ScalaVersionSpecificPackage { + type NonEmptyStream[A] = OneAnd[Stream, A] + + def NonEmptyStream[A](head: A, tail: Stream[A] = Stream.empty): NonEmptyStream[A] = + OneAnd(head, tail) + + @suppressUnusedImportWarningForScalaVersionSpecific + def NonEmptyStream[A](head: A, tail: A*): NonEmptyStream[A] = + OneAnd(head, tail.toStream) +} diff --git a/core/src/main/scala/cats/data/ZipStream.scala b/core/src/main/scala-2.12-/cats/data/ZipStream.scala similarity index 63% rename from core/src/main/scala/cats/data/ZipStream.scala rename to core/src/main/scala-2.12-/cats/data/ZipStream.scala index 8813bc3a46..ca0ecd0e27 100644 --- a/core/src/main/scala/cats/data/ZipStream.scala +++ b/core/src/main/scala-2.12-/cats/data/ZipStream.scala @@ -1,19 +1,18 @@ package cats package data -import instances.{crossVersionEqForLazyList, crossVersionInstancesForLazyList} import kernel.compat.scalaVersionSpecific._ -class ZipStream[A](val value: LazyList[A]) extends AnyVal +class ZipStream[A](val value: Stream[A]) extends AnyVal @suppressUnusedImportWarningForScalaVersionSpecific object ZipStream { - def apply[A](value: LazyList[A]): ZipStream[A] = new ZipStream(value) + def apply[A](value: Stream[A]): ZipStream[A] = new ZipStream(value) implicit val catsDataAlternativeForZipStream: Alternative[ZipStream] with CommutativeApplicative[ZipStream] = new Alternative[ZipStream] with CommutativeApplicative[ZipStream] { - def pure[A](x: A): ZipStream[A] = new ZipStream(LazyList.continually(x)) + def pure[A](x: A): ZipStream[A] = new ZipStream(Stream.continually(x)) override def map[A, B](fa: ZipStream[A])(f: (A) => B): ZipStream[B] = ZipStream(fa.value.map(f)) @@ -24,12 +23,12 @@ object ZipStream { override def product[A, B](fa: ZipStream[A], fb: ZipStream[B]): ZipStream[(A, B)] = ZipStream(fa.value.zip(fb.value)) - def empty[A]: ZipStream[A] = ZipStream(LazyList.empty[A]) + def empty[A]: ZipStream[A] = ZipStream(Stream.empty[A]) def combineK[A](x: ZipStream[A], y: ZipStream[A]): ZipStream[A] = - ZipStream(crossVersionInstancesForLazyList.combineK(x.value, y.value)) + ZipStream(cats.instances.stream.catsStdInstancesForStream.combineK(x.value, y.value)) } implicit def catsDataEqForZipStream[A: Eq]: Eq[ZipStream[A]] = - Eq.by((_: ZipStream[A]).value)(crossVersionEqForLazyList[A]) + Eq.by((_: ZipStream[A]).value)(cats.kernel.instances.stream.catsKernelStdEqForStream[A]) } diff --git a/core/src/main/scala-2.12-/cats/instances/ScalaVersionSpecificParallelInstances.scala b/core/src/main/scala-2.12-/cats/instances/ScalaVersionSpecificParallelInstances.scala new file mode 100644 index 0000000000..e58f29a725 --- /dev/null +++ b/core/src/main/scala-2.12-/cats/instances/ScalaVersionSpecificParallelInstances.scala @@ -0,0 +1,110 @@ +package cats +package instances + +import cats.data._ +import cats.kernel.Semigroup +import cats.syntax.either._ +import cats.{~>, Applicative, Apply, FlatMap, Functor, Monad, NonEmptyParallel, Parallel} +import kernel.compat.scalaVersionSpecific._ + +@suppressUnusedImportWarningForScalaVersionSpecific +trait ParallelInstances extends ParallelInstances1 { + implicit def catsParallelForEitherValidated[E: Semigroup]: Parallel[Either[E, *], Validated[E, *]] = + new Parallel[Either[E, *], Validated[E, *]] { + + def applicative: Applicative[Validated[E, *]] = Validated.catsDataApplicativeErrorForValidated + def monad: Monad[Either[E, *]] = cats.instances.either.catsStdInstancesForEither + + def sequential: Validated[E, *] ~> Either[E, *] = + λ[Validated[E, *] ~> Either[E, *]](_.toEither) + + def parallel: Either[E, *] ~> Validated[E, *] = + λ[Either[E, *] ~> Validated[E, *]](_.toValidated) + } + + implicit def catsParallelForOptionTNestedOption[F[_], M[_]]( + implicit P: Parallel[M, F] + ): Parallel[OptionT[M, *], Nested[F, Option, *]] = new Parallel[OptionT[M, *], Nested[F, Option, *]] { + + implicit val appF: Applicative[F] = P.applicative + implicit val monadM: Monad[M] = P.monad + implicit val appOption: Applicative[Option] = cats.instances.option.catsStdInstancesForOption + + def applicative: Applicative[Nested[F, Option, *]] = cats.data.Nested.catsDataApplicativeForNested[F, Option] + + def monad: Monad[OptionT[M, *]] = cats.data.OptionT.catsDataMonadErrorMonadForOptionT[M] + + def sequential: Nested[F, Option, *] ~> OptionT[M, *] = + λ[Nested[F, Option, *] ~> OptionT[M, *]](nested => OptionT(P.sequential(nested.value))) + + def parallel: OptionT[M, *] ~> Nested[F, Option, *] = + λ[OptionT[M, *] ~> Nested[F, Option, *]](optT => Nested(P.parallel(optT.value))) + } + + implicit def catsStdNonEmptyParallelForZipList[A]: NonEmptyParallel[List, ZipList] = + new NonEmptyParallel[List, ZipList] { + + def flatMap: FlatMap[List] = cats.instances.list.catsStdInstancesForList + def apply: Apply[ZipList] = ZipList.catsDataCommutativeApplyForZipList + + def sequential: ZipList ~> List = + λ[ZipList ~> List](_.value) + + def parallel: List ~> ZipList = + λ[List ~> ZipList](v => new ZipList(v)) + } + + implicit def catsStdNonEmptyParallelForZipVector[A]: NonEmptyParallel[Vector, ZipVector] = + new NonEmptyParallel[Vector, ZipVector] { + + def flatMap: FlatMap[Vector] = cats.instances.vector.catsStdInstancesForVector + def apply: Apply[ZipVector] = ZipVector.catsDataCommutativeApplyForZipVector + + def sequential: ZipVector ~> Vector = + λ[ZipVector ~> Vector](_.value) + + def parallel: Vector ~> ZipVector = + λ[Vector ~> ZipVector](v => new ZipVector(v)) + } + + implicit def catsStdParallelForZipStream[A]: Parallel[Stream, ZipStream] = + new Parallel[Stream, ZipStream] { + + def monad: Monad[Stream] = cats.instances.stream.catsStdInstancesForStream + def applicative: Applicative[ZipStream] = ZipStream.catsDataAlternativeForZipStream + + def sequential: ZipStream ~> Stream = + λ[ZipStream ~> Stream](_.value) + + def parallel: Stream ~> ZipStream = + λ[Stream ~> ZipStream](v => new ZipStream(v)) + } + + implicit def catsParallelForEitherTNestedParallelValidated[F[_], M[_], E: Semigroup]( + implicit P: Parallel[M, F] + ): Parallel[EitherT[M, E, *], Nested[F, Validated[E, *], *]] = + new Parallel[EitherT[M, E, *], Nested[F, Validated[E, *], *]] { + + implicit val appF: Applicative[F] = P.applicative + implicit val monadM: Monad[M] = P.monad + implicit val appValidated: Applicative[Validated[E, *]] = Validated.catsDataApplicativeErrorForValidated + implicit val monadEither: Monad[Either[E, *]] = cats.instances.either.catsStdInstancesForEither + + def applicative: Applicative[Nested[F, Validated[E, *], *]] = + cats.data.Nested.catsDataApplicativeForNested[F, Validated[E, *]] + + def monad: Monad[EitherT[M, E, *]] = cats.data.EitherT.catsDataMonadErrorForEitherT + + def sequential: Nested[F, Validated[E, *], *] ~> EitherT[M, E, *] = + λ[Nested[F, Validated[E, *], *] ~> EitherT[M, E, *]] { nested => + val mva = P.sequential(nested.value) + EitherT(Functor[M].map(mva)(_.toEither)) + } + + def parallel: EitherT[M, E, *] ~> Nested[F, Validated[E, *], *] = + λ[EitherT[M, E, *] ~> Nested[F, Validated[E, *], *]] { eitherT => + val fea = P.parallel(eitherT.value) + Nested(Functor[F].map(fea)(_.toValidated)) + } + } +} diff --git a/core/src/main/scala-2.12-/cats/instances/package.scala b/core/src/main/scala-2.12-/cats/instances/package.scala index 0104506020..c171490fbb 100644 --- a/core/src/main/scala-2.12-/cats/instances/package.scala +++ b/core/src/main/scala-2.12-/cats/instances/package.scala @@ -47,16 +47,4 @@ package object instances { object unit extends UnitInstances object uuid extends UUIDInstances object vector extends VectorInstances with VectorInstancesBinCompat0 - - /** - * Used internally for avoiding version-specific code. - */ - private[cats] def crossVersionInstancesForLazyList: Monad[Stream] with Alternative[Stream] = - stream.catsStdInstancesForStream - - /** - * Used internally for avoiding version-specific code. - */ - private[cats] def crossVersionEqForLazyList[A: Eq]: Eq[Stream[A]] = - stream.catsKernelStdEqForStream[A] } diff --git a/core/src/main/scala-2.13+/cats/compat/lazyList.scala b/core/src/main/scala-2.13+/cats/compat/lazyList.scala deleted file mode 100644 index d9f95edff9..0000000000 --- a/core/src/main/scala-2.13+/cats/compat/lazyList.scala +++ /dev/null @@ -1,7 +0,0 @@ -package cats.compat - -object lazyList { - def toLazyList[A](io: IterableOnce[A]): LazyList[A] = LazyList.from(io) - - def lazyListString: String = "LazyList" -} diff --git a/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala b/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala index 351d456165..8e80c4af1e 100644 --- a/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala +++ b/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala @@ -51,6 +51,29 @@ object NonEmptyLazyList extends NonEmptyLazyListInstances { implicit def catsNonEmptyLazyListOps[A](value: NonEmptyLazyList[A]): NonEmptyLazyListOps[A] = new NonEmptyLazyListOps(value) + + class ZipNonEmptyLazyList[A](val value: NonEmptyLazyList[A]) extends Serializable + + object ZipNonEmptyLazyList { + + def apply[A](nell: NonEmptyLazyList[A]): ZipNonEmptyLazyList[A] = + new ZipNonEmptyLazyList(nell) + + implicit val catsDataCommutativeApplyForZipNonEmptyLazyList: CommutativeApply[ZipNonEmptyLazyList] = + new CommutativeApply[ZipNonEmptyLazyList] { + def ap[A, B](ff: ZipNonEmptyLazyList[A => B])(fa: ZipNonEmptyLazyList[A]): ZipNonEmptyLazyList[B] = + ZipNonEmptyLazyList(ff.value.zipWith(fa.value)(_.apply(_))) + + override def map[A, B](fa: ZipNonEmptyLazyList[A])(f: (A) => B): ZipNonEmptyLazyList[B] = + ZipNonEmptyLazyList(fa.value.map(f)) + + override def product[A, B](fa: ZipNonEmptyLazyList[A], + fb: ZipNonEmptyLazyList[B]): ZipNonEmptyLazyList[(A, B)] = + ZipNonEmptyLazyList(fa.value.zipWith(fb.value) { case (a, b) => (a, b) }) + } + + implicit def catsDataEqForZipNonEmptyLazyList[A: Eq]: Eq[ZipNonEmptyLazyList[A]] = Eq.by(_.value) + } } class NonEmptyLazyListOps[A](private val value: NonEmptyLazyList[A]) extends AnyVal { @@ -362,7 +385,22 @@ sealed abstract private[data] class NonEmptyLazyListInstances extends NonEmptyLa Semigroup[LazyList[A]].asInstanceOf[Semigroup[NonEmptyLazyList[A]]] implicit def catsDataShowForNonEmptyLazyList[A](implicit A: Show[A]): Show[NonEmptyLazyList[A]] = - Show.show[NonEmptyLazyList[A]](nec => s"NonEmpty${Show[LazyList[A]].show(nec.toLazyList)}") + Show.show[NonEmptyLazyList[A]](nell => s"NonEmpty${Show[LazyList[A]].show(nell.toLazyList)}") + + import NonEmptyLazyList.ZipNonEmptyLazyList + + implicit def catsDataParallelForNonEmptyLazyList: NonEmptyParallel[NonEmptyLazyList, ZipNonEmptyLazyList] = + new NonEmptyParallel[NonEmptyLazyList, ZipNonEmptyLazyList] { + + def apply: Apply[ZipNonEmptyLazyList] = ZipNonEmptyLazyList.catsDataCommutativeApplyForZipNonEmptyLazyList + def flatMap: FlatMap[NonEmptyLazyList] = NonEmptyLazyList.catsDataInstancesForNonEmptyLazyList + + def sequential: ZipNonEmptyLazyList ~> NonEmptyLazyList = + λ[ZipNonEmptyLazyList ~> NonEmptyLazyList](_.value) + + def parallel: NonEmptyLazyList ~> ZipNonEmptyLazyList = + λ[NonEmptyLazyList ~> ZipNonEmptyLazyList](nell => new ZipNonEmptyLazyList(nell)) + } } diff --git a/core/src/main/scala-2.13+/cats/data/OneAndLowPriority4.scala b/core/src/main/scala-2.13+/cats/data/OneAndLowPriority4.scala new file mode 100644 index 0000000000..a64f433d26 --- /dev/null +++ b/core/src/main/scala-2.13+/cats/data/OneAndLowPriority4.scala @@ -0,0 +1,46 @@ +package cats +package data + +import scala.annotation.tailrec +import scala.collection.mutable.Builder + +abstract private[data] class OneAndLowPriority4 { + @deprecated("2.0.0-RC2", "Use catsDataComonadForNonEmptyLazyList") + implicit def catsDataComonadForNonEmptyStream: Comonad[OneAnd[Stream, *]] = + new Comonad[OneAnd[Stream, *]] { + def coflatMap[A, B](fa: OneAnd[Stream, A])(f: OneAnd[Stream, A] => B): OneAnd[Stream, B] = { + @tailrec def consume(as: Stream[A], buf: Builder[B, Stream[B]]): Stream[B] = + if (as.isEmpty) buf.result + else { + val tail = as.tail + consume(tail, buf += f(OneAnd(as.head, tail))) + } + OneAnd(f(fa), consume(fa.tail, Stream.newBuilder)) + } + + def extract[A](fa: OneAnd[Stream, A]): A = + fa.head + + def map[A, B](fa: OneAnd[Stream, A])(f: A => B): OneAnd[Stream, B] = + fa.map(f)(cats.instances.stream.catsStdInstancesForStream) + } + + implicit val catsDataComonadForNonEmptyLazyList: Comonad[OneAnd[LazyList, *]] = + new Comonad[OneAnd[LazyList, *]] { + def coflatMap[A, B](fa: OneAnd[LazyList, A])(f: OneAnd[LazyList, A] => B): OneAnd[LazyList, B] = { + @tailrec def consume(as: LazyList[A], buf: Builder[B, LazyList[B]]): LazyList[B] = + if (as.isEmpty) buf.result + else { + val tail = as.tail + consume(tail, buf += f(OneAnd(as.head, tail))) + } + OneAnd(f(fa), consume(fa.tail, LazyList.newBuilder)) + } + + def extract[A](fa: OneAnd[LazyList, A]): A = + fa.head + + def map[A, B](fa: OneAnd[LazyList, A])(f: A => B): OneAnd[LazyList, B] = + fa.map(f)(cats.instances.lazyList.catsStdInstancesForLazyList) + } +} diff --git a/core/src/main/scala-2.13+/cats/data/ScalaVersionSpecificPackage.scala b/core/src/main/scala-2.13+/cats/data/ScalaVersionSpecificPackage.scala index 6ca3d1911e..7a582b21d3 100644 --- a/core/src/main/scala-2.13+/cats/data/ScalaVersionSpecificPackage.scala +++ b/core/src/main/scala-2.13+/cats/data/ScalaVersionSpecificPackage.scala @@ -1,7 +1,19 @@ package cats - package data +import kernel.compat.scalaVersionSpecific._ + abstract private[data] class ScalaVersionSpecificPackage { type NonEmptyLazyList[+A] = NonEmptyLazyList.Type[A] + @deprecated("2.0.0-RC2", "Use NonEmptyLazyList") + type NonEmptyStream[A] = OneAnd[Stream, A] + + @deprecated("2.0.0-RC2", "Use NonEmptyLazyList") + def NonEmptyStream[A](head: A, tail: Stream[A]): NonEmptyStream[A] = + OneAnd(head, tail) + + @suppressUnusedImportWarningForScalaVersionSpecific + @deprecated("2.0.0-RC2", "Use NonEmptyLazyList") + def NonEmptyStream[A](head: A, tail: A*): NonEmptyStream[A] = + OneAnd(head, tail.toStream) } diff --git a/core/src/main/scala-2.13+/cats/data/ZipLazyList.scala b/core/src/main/scala-2.13+/cats/data/ZipLazyList.scala new file mode 100644 index 0000000000..20c4832560 --- /dev/null +++ b/core/src/main/scala-2.13+/cats/data/ZipLazyList.scala @@ -0,0 +1,31 @@ +package cats +package data + +class ZipLazyList[A](val value: LazyList[A]) extends AnyVal + +object ZipLazyList { + + def apply[A](value: LazyList[A]): ZipLazyList[A] = new ZipLazyList(value) + + implicit val catsDataAlternativeForZipLazyList: Alternative[ZipLazyList] with CommutativeApplicative[ZipLazyList] = + new Alternative[ZipLazyList] with CommutativeApplicative[ZipLazyList] { + def pure[A](x: A): ZipLazyList[A] = new ZipLazyList(LazyList.continually(x)) + + override def map[A, B](fa: ZipLazyList[A])(f: (A) => B): ZipLazyList[B] = + ZipLazyList(fa.value.map(f)) + + def ap[A, B](ff: ZipLazyList[A => B])(fa: ZipLazyList[A]): ZipLazyList[B] = + ZipLazyList(ff.value.lazyZip(fa.value).map(_.apply(_))) + + override def product[A, B](fa: ZipLazyList[A], fb: ZipLazyList[B]): ZipLazyList[(A, B)] = + ZipLazyList(fa.value.zip(fb.value)) + + def empty[A]: ZipLazyList[A] = ZipLazyList(LazyList.empty[A]) + + def combineK[A](x: ZipLazyList[A], y: ZipLazyList[A]): ZipLazyList[A] = + ZipLazyList(cats.instances.lazyList.catsStdInstancesForLazyList.combineK(x.value, y.value)) + } + + implicit def catsDataEqForZipLazyList[A: Eq]: Eq[ZipLazyList[A]] = + Eq.by((_: ZipLazyList[A]).value)(cats.kernel.instances.lazyList.catsKernelStdEqForLazyList[A]) +} diff --git a/core/src/main/scala-2.13+/cats/data/ZipStream.scala b/core/src/main/scala-2.13+/cats/data/ZipStream.scala new file mode 100644 index 0000000000..3287ec727a --- /dev/null +++ b/core/src/main/scala-2.13+/cats/data/ZipStream.scala @@ -0,0 +1,36 @@ +package cats +package data + +import kernel.compat.scalaVersionSpecific._ + +@deprecated("2.0.0-RC2", "Use ZipLazyList") +class ZipStream[A](val value: Stream[A]) extends AnyVal + +@suppressUnusedImportWarningForScalaVersionSpecific +@deprecated("2.0.0-RC2", "Use ZipLazyList") +object ZipStream { + + def apply[A](value: Stream[A]): ZipStream[A] = new ZipStream(value) + + implicit val catsDataAlternativeForZipStream: Alternative[ZipStream] with CommutativeApplicative[ZipStream] = + new Alternative[ZipStream] with CommutativeApplicative[ZipStream] { + def pure[A](x: A): ZipStream[A] = new ZipStream(Stream.continually(x)) + + override def map[A, B](fa: ZipStream[A])(f: (A) => B): ZipStream[B] = + ZipStream(fa.value.map(f)) + + def ap[A, B](ff: ZipStream[A => B])(fa: ZipStream[A]): ZipStream[B] = + ZipStream(ff.value.lazyZip(fa.value).map(_.apply(_))) + + override def product[A, B](fa: ZipStream[A], fb: ZipStream[B]): ZipStream[(A, B)] = + ZipStream(fa.value.zip(fb.value)) + + def empty[A]: ZipStream[A] = ZipStream(Stream.empty[A]) + + def combineK[A](x: ZipStream[A], y: ZipStream[A]): ZipStream[A] = + ZipStream(cats.instances.stream.catsStdInstancesForStream.combineK(x.value, y.value)) + } + + implicit def catsDataEqForZipStream[A: Eq]: Eq[ZipStream[A]] = + Eq.by((_: ZipStream[A]).value)(cats.kernel.instances.stream.catsKernelStdEqForStream[A]) +} diff --git a/core/src/main/scala-2.13+/cats/instances/ScalaVersionSpecificParallelInstances.scala b/core/src/main/scala-2.13+/cats/instances/ScalaVersionSpecificParallelInstances.scala new file mode 100644 index 0000000000..3c21117d8f --- /dev/null +++ b/core/src/main/scala-2.13+/cats/instances/ScalaVersionSpecificParallelInstances.scala @@ -0,0 +1,124 @@ +package cats +package instances + +import cats.data._ +import cats.kernel.Semigroup +import cats.syntax.either._ +import cats.{~>, Applicative, Apply, FlatMap, Functor, Monad, NonEmptyParallel, Parallel} +import kernel.compat.scalaVersionSpecific._ + +@suppressUnusedImportWarningForScalaVersionSpecific +trait ParallelInstances extends ParallelInstances1 { + implicit def catsParallelForEitherValidated[E: Semigroup]: Parallel[Either[E, *], Validated[E, *]] = + new Parallel[Either[E, *], Validated[E, *]] { + + def applicative: Applicative[Validated[E, *]] = Validated.catsDataApplicativeErrorForValidated + def monad: Monad[Either[E, *]] = cats.instances.either.catsStdInstancesForEither + + def sequential: Validated[E, *] ~> Either[E, *] = + λ[Validated[E, *] ~> Either[E, *]](_.toEither) + + def parallel: Either[E, *] ~> Validated[E, *] = + λ[Either[E, *] ~> Validated[E, *]](_.toValidated) + } + + implicit def catsParallelForOptionTNestedOption[F[_], M[_]]( + implicit P: Parallel[M, F] + ): Parallel[OptionT[M, *], Nested[F, Option, *]] = new Parallel[OptionT[M, *], Nested[F, Option, *]] { + + implicit val appF: Applicative[F] = P.applicative + implicit val monadM: Monad[M] = P.monad + implicit val appOption: Applicative[Option] = cats.instances.option.catsStdInstancesForOption + + def applicative: Applicative[Nested[F, Option, *]] = cats.data.Nested.catsDataApplicativeForNested[F, Option] + + def monad: Monad[OptionT[M, *]] = cats.data.OptionT.catsDataMonadErrorMonadForOptionT[M] + + def sequential: Nested[F, Option, *] ~> OptionT[M, *] = + λ[Nested[F, Option, *] ~> OptionT[M, *]](nested => OptionT(P.sequential(nested.value))) + + def parallel: OptionT[M, *] ~> Nested[F, Option, *] = + λ[OptionT[M, *] ~> Nested[F, Option, *]](optT => Nested(P.parallel(optT.value))) + } + + implicit def catsStdNonEmptyParallelForZipList[A]: NonEmptyParallel[List, ZipList] = + new NonEmptyParallel[List, ZipList] { + + def flatMap: FlatMap[List] = cats.instances.list.catsStdInstancesForList + def apply: Apply[ZipList] = ZipList.catsDataCommutativeApplyForZipList + + def sequential: ZipList ~> List = + λ[ZipList ~> List](_.value) + + def parallel: List ~> ZipList = + λ[List ~> ZipList](v => new ZipList(v)) + } + + implicit def catsStdNonEmptyParallelForZipVector[A]: NonEmptyParallel[Vector, ZipVector] = + new NonEmptyParallel[Vector, ZipVector] { + + def flatMap: FlatMap[Vector] = cats.instances.vector.catsStdInstancesForVector + def apply: Apply[ZipVector] = ZipVector.catsDataCommutativeApplyForZipVector + + def sequential: ZipVector ~> Vector = + λ[ZipVector ~> Vector](_.value) + + def parallel: Vector ~> ZipVector = + λ[Vector ~> ZipVector](v => new ZipVector(v)) + } + + @deprecated("2.0.0-RC2", "Use catsStdParallelForZipLazyList") + implicit def catsStdParallelForZipStream[A]: Parallel[Stream, ZipStream] = + new Parallel[Stream, ZipStream] { + + def monad: Monad[Stream] = cats.instances.stream.catsStdInstancesForStream + def applicative: Applicative[ZipStream] = ZipStream.catsDataAlternativeForZipStream + + def sequential: ZipStream ~> Stream = + λ[ZipStream ~> Stream](_.value) + + def parallel: Stream ~> ZipStream = + λ[Stream ~> ZipStream](v => new ZipStream(v)) + } + + implicit def catsStdParallelForZipLazyList[A]: Parallel[LazyList, ZipLazyList] = + new Parallel[LazyList, ZipLazyList] { + + def monad: Monad[LazyList] = cats.instances.lazyList.catsStdInstancesForLazyList + def applicative: Applicative[ZipLazyList] = ZipLazyList.catsDataAlternativeForZipLazyList + + def sequential: ZipLazyList ~> LazyList = + λ[ZipLazyList ~> LazyList](_.value) + + def parallel: LazyList ~> ZipLazyList = + λ[LazyList ~> ZipLazyList](v => new ZipLazyList(v)) + } + + implicit def catsParallelForEitherTNestedParallelValidated[F[_], M[_], E: Semigroup]( + implicit P: Parallel[M, F] + ): Parallel[EitherT[M, E, *], Nested[F, Validated[E, *], *]] = + new Parallel[EitherT[M, E, *], Nested[F, Validated[E, *], *]] { + + implicit val appF: Applicative[F] = P.applicative + implicit val monadM: Monad[M] = P.monad + implicit val appValidated: Applicative[Validated[E, *]] = Validated.catsDataApplicativeErrorForValidated + implicit val monadEither: Monad[Either[E, *]] = cats.instances.either.catsStdInstancesForEither + + def applicative: Applicative[Nested[F, Validated[E, *], *]] = + cats.data.Nested.catsDataApplicativeForNested[F, Validated[E, *]] + + def monad: Monad[EitherT[M, E, *]] = cats.data.EitherT.catsDataMonadErrorForEitherT + + def sequential: Nested[F, Validated[E, *], *] ~> EitherT[M, E, *] = + λ[Nested[F, Validated[E, *], *] ~> EitherT[M, E, *]] { nested => + val mva = P.sequential(nested.value) + EitherT(Functor[M].map(mva)(_.toEither)) + } + + def parallel: EitherT[M, E, *] ~> Nested[F, Validated[E, *], *] = + λ[EitherT[M, E, *] ~> Nested[F, Validated[E, *], *]] { eitherT => + val fea = P.parallel(eitherT.value) + Nested(Functor[F].map(fea)(_.toValidated)) + } + } +} diff --git a/core/src/main/scala-2.13+/cats/instances/package.scala b/core/src/main/scala-2.13+/cats/instances/package.scala index 06796ef6db..fa49782947 100644 --- a/core/src/main/scala-2.13+/cats/instances/package.scala +++ b/core/src/main/scala-2.13+/cats/instances/package.scala @@ -40,6 +40,8 @@ package object instances { object short extends ShortInstances object sortedMap extends SortedMapInstances with SortedMapInstancesBinCompat0 with SortedMapInstancesBinCompat1 object sortedSet extends SortedSetInstances with SortedSetInstancesBinCompat0 + + @deprecated("2.0.0-RC2", "Use cats.instances.lazyList") object stream extends StreamInstances with StreamInstancesBinCompat0 object lazyList extends LazyListInstances object string extends StringInstances @@ -48,16 +50,4 @@ package object instances { object unit extends UnitInstances object uuid extends UUIDInstances object vector extends VectorInstances with VectorInstancesBinCompat0 - - /** - * Used internally for avoiding version-specific code. - */ - private[cats] def crossVersionInstancesForLazyList: Monad[LazyList] with Alternative[LazyList] = - lazyList.catsStdInstancesForLazyList - - /** - * Used internally for avoiding version-specific code. - */ - private[cats] def crossVersionEqForLazyList[A: Eq]: Eq[LazyList[A]] = - lazyList.catsKernelStdEqForLazyList[A] } diff --git a/core/src/main/scala/cats/data/NonEmptyVector.scala b/core/src/main/scala/cats/data/NonEmptyVector.scala index 773acde5e3..c7e5933f61 100644 --- a/core/src/main/scala/cats/data/NonEmptyVector.scala +++ b/core/src/main/scala/cats/data/NonEmptyVector.scala @@ -371,7 +371,7 @@ sealed abstract private[data] class NonEmptyVectorInstances { implicit def catsDataSemigroupForNonEmptyVector[A]: Semigroup[NonEmptyVector[A]] = catsDataInstancesForNonEmptyVector.algebra - implicit def catsDataParallelForNonEmptyVector[A]: NonEmptyParallel[NonEmptyVector, ZipNonEmptyVector] = + implicit def catsDataParallelForNonEmptyVector: NonEmptyParallel[NonEmptyVector, ZipNonEmptyVector] = new NonEmptyParallel[NonEmptyVector, ZipNonEmptyVector] { def apply: Apply[ZipNonEmptyVector] = ZipNonEmptyVector.catsDataCommutativeApplyForZipNonEmptyVector diff --git a/core/src/main/scala/cats/data/OneAnd.scala b/core/src/main/scala/cats/data/OneAnd.scala index 92cfdde55e..8d775b652a 100644 --- a/core/src/main/scala/cats/data/OneAnd.scala +++ b/core/src/main/scala/cats/data/OneAnd.scala @@ -2,8 +2,6 @@ package cats package data import scala.annotation.tailrec -import scala.collection.mutable.Builder -import cats.instances.crossVersionInstancesForLazyList import kernel.compat.scalaVersionSpecific._ /** @@ -192,27 +190,6 @@ sealed abstract private[data] class OneAndInstances extends OneAndLowPriority0 { } } -sealed abstract private[data] class OneAndLowPriority4 { - implicit val catsDataComonadForNonEmptyStream: Comonad[OneAnd[LazyList, *]] = - new Comonad[OneAnd[LazyList, *]] { - def coflatMap[A, B](fa: OneAnd[LazyList, A])(f: OneAnd[LazyList, A] => B): OneAnd[LazyList, B] = { - @tailrec def consume(as: LazyList[A], buf: Builder[B, LazyList[B]]): LazyList[B] = - if (as.isEmpty) buf.result - else { - val tail = as.tail - consume(tail, buf += f(OneAnd(as.head, tail))) - } - OneAnd(f(fa), consume(fa.tail, LazyList.newBuilder)) - } - - def extract[A](fa: OneAnd[LazyList, A]): A = - fa.head - - def map[A, B](fa: OneAnd[LazyList, A])(f: A => B): OneAnd[LazyList, B] = - fa.map(f)(crossVersionInstancesForLazyList) - } -} - sealed abstract private[data] class OneAndLowPriority3 extends OneAndLowPriority4 { implicit def catsDataFunctorForOneAnd[F[_]](implicit F: Functor[F]): Functor[OneAnd[F, *]] = diff --git a/core/src/main/scala/cats/data/package.scala b/core/src/main/scala/cats/data/package.scala index 30619dcdfb..ca3e350143 100644 --- a/core/src/main/scala/cats/data/package.scala +++ b/core/src/main/scala/cats/data/package.scala @@ -1,10 +1,7 @@ package cats -import kernel.compat.scalaVersionSpecific._ -import compat.lazyList.toLazyList package object data extends ScalaVersionSpecificPackage { - type NonEmptyStream[A] = OneAnd[LazyList, A] type ValidatedNel[+E, +A] = Validated[NonEmptyList[E], A] type IorNel[+B, +A] = Ior[NonEmptyList[B], A] type IorNec[+B, +A] = Ior[NonEmptyChain[B], A] @@ -14,13 +11,6 @@ package object data extends ScalaVersionSpecificPackage { type EitherNes[E, +A] = Either[NonEmptySet[E], A] type ValidatedNec[+E, +A] = Validated[NonEmptyChain[E], A] - def NonEmptyStream[A](head: A, tail: LazyList[A] = LazyList.empty): NonEmptyStream[A] = - OneAnd(head, tail) - - @suppressUnusedImportWarningForScalaVersionSpecific - def NonEmptyStream[A](head: A, tail: A*): NonEmptyStream[A] = - OneAnd(head, toLazyList(tail)) - type NonEmptyMap[K, +A] = NonEmptyMapImpl.Type[K, A] val NonEmptyMap = NonEmptyMapImpl @@ -93,7 +83,4 @@ package object data extends ScalaVersionSpecificPackage { def apply[S, A](f: S => A, s: S): Store[S, A] = RepresentableStore[S => *, S, A](f, s) } - - type ZipLazyList[A] = ZipStream[A] - val ZipLazyList = ZipStream } diff --git a/core/src/main/scala/cats/instances/parallel.scala b/core/src/main/scala/cats/instances/parallel.scala index 213f0698d2..8c9017a100 100644 --- a/core/src/main/scala/cats/instances/parallel.scala +++ b/core/src/main/scala/cats/instances/parallel.scala @@ -4,110 +4,7 @@ package instances import cats.data._ import cats.kernel.Semigroup import cats.syntax.either._ -import cats.{~>, Applicative, Apply, FlatMap, Functor, Monad, NonEmptyParallel, Parallel} -import kernel.compat.scalaVersionSpecific._ - -@suppressUnusedImportWarningForScalaVersionSpecific -trait ParallelInstances extends ParallelInstances1 { - implicit def catsParallelForEitherValidated[E: Semigroup]: Parallel[Either[E, *], Validated[E, *]] = - new Parallel[Either[E, *], Validated[E, *]] { - - def applicative: Applicative[Validated[E, *]] = Validated.catsDataApplicativeErrorForValidated - def monad: Monad[Either[E, *]] = cats.instances.either.catsStdInstancesForEither - - def sequential: Validated[E, *] ~> Either[E, *] = - λ[Validated[E, *] ~> Either[E, *]](_.toEither) - - def parallel: Either[E, *] ~> Validated[E, *] = - λ[Either[E, *] ~> Validated[E, *]](_.toValidated) - } - - implicit def catsParallelForOptionTNestedOption[F[_], M[_]]( - implicit P: Parallel[M, F] - ): Parallel[OptionT[M, *], Nested[F, Option, *]] = new Parallel[OptionT[M, *], Nested[F, Option, *]] { - - implicit val appF: Applicative[F] = P.applicative - implicit val monadM: Monad[M] = P.monad - implicit val appOption: Applicative[Option] = cats.instances.option.catsStdInstancesForOption - - def applicative: Applicative[Nested[F, Option, *]] = cats.data.Nested.catsDataApplicativeForNested[F, Option] - - def monad: Monad[OptionT[M, *]] = cats.data.OptionT.catsDataMonadErrorMonadForOptionT[M] - - def sequential: Nested[F, Option, *] ~> OptionT[M, *] = - λ[Nested[F, Option, *] ~> OptionT[M, *]](nested => OptionT(P.sequential(nested.value))) - - def parallel: OptionT[M, *] ~> Nested[F, Option, *] = - λ[OptionT[M, *] ~> Nested[F, Option, *]](optT => Nested(P.parallel(optT.value))) - } - - implicit def catsStdNonEmptyParallelForZipList[A]: NonEmptyParallel[List, ZipList] = - new NonEmptyParallel[List, ZipList] { - - def flatMap: FlatMap[List] = cats.instances.list.catsStdInstancesForList - def apply: Apply[ZipList] = ZipList.catsDataCommutativeApplyForZipList - - def sequential: ZipList ~> List = - λ[ZipList ~> List](_.value) - - def parallel: List ~> ZipList = - λ[List ~> ZipList](v => new ZipList(v)) - } - - implicit def catsStdNonEmptyParallelForZipVector[A]: NonEmptyParallel[Vector, ZipVector] = - new NonEmptyParallel[Vector, ZipVector] { - - def flatMap: FlatMap[Vector] = cats.instances.vector.catsStdInstancesForVector - def apply: Apply[ZipVector] = ZipVector.catsDataCommutativeApplyForZipVector - - def sequential: ZipVector ~> Vector = - λ[ZipVector ~> Vector](_.value) - - def parallel: Vector ~> ZipVector = - λ[Vector ~> ZipVector](v => new ZipVector(v)) - } - - implicit def catsStdParallelForZipStream[A]: Parallel[LazyList, ZipStream] = - new Parallel[LazyList, ZipStream] { - - def monad: Monad[LazyList] = cats.instances.crossVersionInstancesForLazyList - def applicative: Applicative[ZipStream] = ZipStream.catsDataAlternativeForZipStream - - def sequential: ZipStream ~> LazyList = - λ[ZipStream ~> LazyList](_.value) - - def parallel: LazyList ~> ZipStream = - λ[LazyList ~> ZipStream](v => new ZipStream(v)) - } - - implicit def catsParallelForEitherTNestedParallelValidated[F[_], M[_], E: Semigroup]( - implicit P: Parallel[M, F] - ): Parallel[EitherT[M, E, *], Nested[F, Validated[E, *], *]] = - new Parallel[EitherT[M, E, *], Nested[F, Validated[E, *], *]] { - - implicit val appF: Applicative[F] = P.applicative - implicit val monadM: Monad[M] = P.monad - implicit val appValidated: Applicative[Validated[E, *]] = Validated.catsDataApplicativeErrorForValidated - implicit val monadEither: Monad[Either[E, *]] = cats.instances.either.catsStdInstancesForEither - - def applicative: Applicative[Nested[F, Validated[E, *], *]] = - cats.data.Nested.catsDataApplicativeForNested[F, Validated[E, *]] - - def monad: Monad[EitherT[M, E, *]] = cats.data.EitherT.catsDataMonadErrorForEitherT - - def sequential: Nested[F, Validated[E, *], *] ~> EitherT[M, E, *] = - λ[Nested[F, Validated[E, *], *] ~> EitherT[M, E, *]] { nested => - val mva = P.sequential(nested.value) - EitherT(Functor[M].map(mva)(_.toEither)) - } - - def parallel: EitherT[M, E, *] ~> Nested[F, Validated[E, *], *] = - λ[EitherT[M, E, *] ~> Nested[F, Validated[E, *], *]] { eitherT => - val fea = P.parallel(eitherT.value) - Nested(Functor[F].map(fea)(_.toValidated)) - } - } -} +import cats.{~>, Applicative, Monad, Parallel} private[instances] trait ParallelInstances1 { implicit def catsParallelForEitherTNestedValidated[M[_]: Monad, E: Semigroup] diff --git a/core/src/main/scala/cats/instances/sortedSet.scala b/core/src/main/scala/cats/instances/sortedSet.scala index 3dfb002144..300410ee11 100644 --- a/core/src/main/scala/cats/instances/sortedSet.scala +++ b/core/src/main/scala/cats/instances/sortedSet.scala @@ -2,10 +2,10 @@ package cats package instances import cats.kernel.{BoundedSemilattice, Hash, Order} +import cats.kernel.instances.StaticMethods import scala.collection.immutable.SortedSet import scala.annotation.tailrec import cats.implicits._ -import compat.lazyList._ trait SortedSetInstances extends SortedSetInstances1 { @@ -93,14 +93,12 @@ trait SortedSetInstancesBinCompat0 { class SortedSetOrder[A: Order] extends Order[SortedSet[A]] { def compare(a1: SortedSet[A], a2: SortedSet[A]): Int = Order[Int].compare(a1.size, a2.size) match { - case 0 => Order.compare(toLazyList(a1), toLazyList(a2)) + case 0 => StaticMethods.iteratorCompare(a1.iterator, a2.iterator) case x => x } - override def eqv(s1: SortedSet[A], s2: SortedSet[A]): Boolean = { - implicit val x = Order[A].toOrdering - toLazyList(s1).corresponds(toLazyList(s2))(Order[A].eqv) - } + override def eqv(s1: SortedSet[A], s2: SortedSet[A]): Boolean = + StaticMethods.iteratorEq(s1.iterator, s2.iterator) } class SortedSetHash[A: Order: Hash] extends Hash[SortedSet[A]] { @@ -124,10 +122,8 @@ class SortedSetHash[A: Order: Hash] extends Hash[SortedSet[A]] { h = mixLast(h, c) finalizeHash(h, n) } - override def eqv(s1: SortedSet[A], s2: SortedSet[A]): Boolean = { - implicit val x = Order[A].toOrdering - toLazyList(s1).corresponds(toLazyList(s2))(Order[A].eqv) - } + override def eqv(s1: SortedSet[A], s2: SortedSet[A]): Boolean = + StaticMethods.iteratorEq(s1.iterator, s2.iterator)(Order[A]) } class SortedSetSemilattice[A: Order] extends BoundedSemilattice[SortedSet[A]] { diff --git a/kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala b/kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala index af1a8e4457..5bdcc62ca3 100644 --- a/kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala +++ b/kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala @@ -132,7 +132,7 @@ class Tests extends AnyFunSuiteLike with Discipline { checkAll("Eq[List[HasEq[Int]]]", EqTests[List[HasEq[Int]]].eqv) checkAll("Eq[Option[HasEq[Int]]]", EqTests[Option[HasEq[Int]]].eqv) checkAll("Eq[Vector[HasEq[Int]]]", EqTests[Vector[HasEq[Int]]].eqv) - checkAll("Eq[Stream[HasEq[Int]]]", EqTests[LazyList[HasEq[Int]]].eqv) + checkAll("Eq[Stream[HasEq[Int]]]", EqTests[Stream[HasEq[Int]]].eqv) checkAll("Eq[Queue[HasEq[Int]]]", EqTests[Queue[HasEq[Int]]].eqv) checkAll("PartialOrder[Set[Int]]", PartialOrderTests[Set[Int]].partialOrder) @@ -145,7 +145,7 @@ class Tests extends AnyFunSuiteLike with Discipline { checkAll("PartialOrder[Option[HasPartialOrder[Int]]]", PartialOrderTests[Option[HasPartialOrder[Int]]].partialOrder) checkAll("PartialOrder[List[HasPartialOrder[Int]]]", PartialOrderTests[List[HasPartialOrder[Int]]].partialOrder) checkAll("PartialOrder[Vector[HasPartialOrder[Int]]]", PartialOrderTests[Vector[HasPartialOrder[Int]]].partialOrder) - checkAll("PartialOrder[Stream[HasPartialOrder[Int]]]", PartialOrderTests[LazyList[HasPartialOrder[Int]]].partialOrder) + checkAll("PartialOrder[Stream[HasPartialOrder[Int]]]", PartialOrderTests[Stream[HasPartialOrder[Int]]].partialOrder) checkAll("PartialOrder[Queue[HasPartialOrder[Int]]]", PartialOrderTests[Queue[HasPartialOrder[Int]]].partialOrder) checkAll("Semilattice.asMeetPartialOrder[Set[Int]]", PartialOrderTests(Semilattice.asMeetPartialOrder[Set[Int]]).partialOrder) @@ -170,7 +170,7 @@ class Tests extends AnyFunSuiteLike with Discipline { checkAll("Order[Option[String]]", OrderTests[Option[String]].order) checkAll("Order[List[String]", OrderTests[List[String]].order) checkAll("Order[Vector[Int]]", OrderTests[Vector[Int]].order) - checkAll("Order[Stream[Int]]", OrderTests[LazyList[Int]].order) + checkAll("Order[Stream[Int]]", OrderTests[Stream[Int]].order) checkAll("Order[Queue[Int]]", OrderTests[Queue[Int]].order) checkAll("fromOrdering[Int]", OrderTests(Order.fromOrdering[Int]).order) checkAll("Order.reverse(Order[Int])", OrderTests(Order.reverse(Order[Int])).order) @@ -211,8 +211,8 @@ class Tests extends AnyFunSuiteLike with Discipline { checkAll("Monoid[List[Int]]", SerializableTests.serializable(Monoid[List[Int]])) checkAll("Monoid[Vector[Int]]", MonoidTests[Vector[Int]].monoid) checkAll("Monoid[Vector[Int]]", SerializableTests.serializable(Monoid[Vector[Int]])) - checkAll("Monoid[Stream[Int]]", MonoidTests[LazyList[Int]].monoid) - checkAll("Monoid[Stream[Int]]", SerializableTests.serializable(Monoid[LazyList[Int]])) + checkAll("Monoid[Stream[Int]]", MonoidTests[Stream[Int]].monoid) + checkAll("Monoid[Stream[Int]]", SerializableTests.serializable(Monoid[Stream[Int]])) checkAll("Monoid[List[String]]", MonoidTests[List[String]].monoid) checkAll("Monoid[List[String]]", SerializableTests.serializable(Monoid[List[String]])) checkAll("Monoid[Map[String, String]]", MonoidTests[Map[String, String]].monoid) @@ -270,7 +270,7 @@ class Tests extends AnyFunSuiteLike with Discipline { checkAll("Hash[Option[String]]", HashTests[Option[String]].hash) checkAll("Hash[List[String]]", HashTests[List[String]].hash) checkAll("Hash[Vector[Int]]", HashTests[Vector[Int]].hash) - checkAll("Hash[Stream[Int]]", HashTests[LazyList[Int]].hash) + checkAll("Hash[Stream[Int]]", HashTests[Stream[Int]].hash) checkAll("Hash[Set[Int]]", HashTests[Set[Int]].hash) checkAll("Hash[(Int, String)]", HashTests[(Int, String)].hash) checkAll("Hash[Either[Int, String]]", HashTests[Either[Int, String]].hash) diff --git a/kernel/src/main/scala-2.12-/cats/kernel/compat/scalaVersionSpecific.scala b/kernel/src/main/scala-2.12-/cats/kernel/compat/scalaVersionSpecific.scala index a6a1f8058d..a1c8b751e4 100644 --- a/kernel/src/main/scala-2.12-/cats/kernel/compat/scalaVersionSpecific.scala +++ b/kernel/src/main/scala-2.12-/cats/kernel/compat/scalaVersionSpecific.scala @@ -9,8 +9,6 @@ private[cats] object scalaVersionSpecific { */ class suppressUnusedImportWarningForScalaVersionSpecific extends Annotation with StaticAnnotation - type LazyList[+A] = Stream[A] - val LazyList = Stream type IterableOnce[+A] = TraversableOnce[A] implicit class traversableOnceExtension[A](private val to: TraversableOnce[A]) extends AnyVal { diff --git a/kernel/src/main/scala-2.13+/cats/kernel/instances/AllInstances.scala b/kernel/src/main/scala-2.13+/cats/kernel/instances/AllInstances.scala index 42ac2cfc90..793b63d5b6 100644 --- a/kernel/src/main/scala-2.13+/cats/kernel/instances/AllInstances.scala +++ b/kernel/src/main/scala-2.13+/cats/kernel/instances/AllInstances.scala @@ -26,6 +26,7 @@ trait AllInstances with QueueInstances with SetInstances with ShortInstances + with StreamInstances with StringInstances with SymbolInstances with TupleInstances diff --git a/laws/src/main/scala-2.12-/cats/laws/discipline/ScalaVersionSpecific.scala b/laws/src/main/scala-2.12-/cats/laws/discipline/ScalaVersionSpecific.scala index 09bd2d0daa..7280f132c7 100644 --- a/laws/src/main/scala-2.12-/cats/laws/discipline/ScalaVersionSpecific.scala +++ b/laws/src/main/scala-2.12-/cats/laws/discipline/ScalaVersionSpecific.scala @@ -2,6 +2,12 @@ package cats package laws package discipline +import cats.data.ZipStream +import org.scalacheck.Arbitrary + private[discipline] object ScalaVersionSpecific { - trait ArbitraryInstances + trait ArbitraryInstances { + implicit def catsLawsArbitraryForZipStream[A](implicit A: Arbitrary[A]): Arbitrary[ZipStream[A]] = + Arbitrary(implicitly[Arbitrary[Stream[A]]].arbitrary.map(v => new ZipStream(v))) + } } diff --git a/laws/src/main/scala-2.13+/cats/laws/discipline/ScalaVersionSpecific.scala b/laws/src/main/scala-2.13+/cats/laws/discipline/ScalaVersionSpecific.scala index 26eaa00240..00ec04c8dc 100644 --- a/laws/src/main/scala-2.13+/cats/laws/discipline/ScalaVersionSpecific.scala +++ b/laws/src/main/scala-2.13+/cats/laws/discipline/ScalaVersionSpecific.scala @@ -1,19 +1,32 @@ package cats.laws.discipline -import cats.data.NonEmptyLazyList +import cats.data.{NonEmptyLazyList, ZipLazyList, ZipStream} +import cats.data.NonEmptyLazyList.ZipNonEmptyLazyList import org.scalacheck.{Arbitrary, Cogen} private[discipline] object ScalaVersionSpecific { trait ArbitraryInstances { + @deprecated("2.0.0-RC2", "Use catsLawsArbitraryForZipLazyList") + implicit def catsLawsArbitraryForZipStream[A](implicit A: Arbitrary[A]): Arbitrary[ZipStream[A]] = + Arbitrary(implicitly[Arbitrary[Stream[A]]].arbitrary.map(v => new ZipStream(v))) + + implicit def catsLawsArbitraryForZipLazyList[A](implicit A: Arbitrary[A]): Arbitrary[ZipLazyList[A]] = + Arbitrary(implicitly[Arbitrary[LazyList[A]]].arbitrary.map(v => new ZipLazyList(v))) implicit def catsLawsArbitraryForNonEmptyLazyList[A](implicit A: Arbitrary[A]): Arbitrary[NonEmptyLazyList[A]] = Arbitrary( implicitly[Arbitrary[LazyList[A]]].arbitrary .flatMap(fa => A.arbitrary.map(a => NonEmptyLazyList.fromLazyListPrepend(a, fa))) ) + implicit def catsLawsCogenForNonEmptyLazyList[A](implicit A: Cogen[A]): Cogen[NonEmptyLazyList[A]] = Cogen[LazyList[A]].contramap(_.toLazyList) + implicit def catsLawsArbitraryForZipNonEmptyLazyList[A]( + implicit A: Arbitrary[A] + ): Arbitrary[ZipNonEmptyLazyList[A]] = + Arbitrary(implicitly[Arbitrary[NonEmptyLazyList[A]]].arbitrary.map(nev => new ZipNonEmptyLazyList(nev))) + } } diff --git a/laws/src/main/scala/cats/laws/discipline/arbitrary.scala b/laws/src/main/scala/cats/laws/discipline/arbitrary.scala index 1772fec0a4..20b1d3f7ad 100644 --- a/laws/src/main/scala/cats/laws/discipline/arbitrary.scala +++ b/laws/src/main/scala/cats/laws/discipline/arbitrary.scala @@ -69,9 +69,6 @@ object arbitrary extends ArbitraryInstances0 with ScalaVersionSpecific.Arbitrary implicit def catsLawsArbitraryForZipList[A](implicit A: Arbitrary[A]): Arbitrary[ZipList[A]] = Arbitrary(implicitly[Arbitrary[List[A]]].arbitrary.map(v => new ZipList(v))) - implicit def catsLawsArbitraryForZipStream[A](implicit A: Arbitrary[A]): Arbitrary[ZipStream[A]] = - Arbitrary(implicitly[Arbitrary[LazyList[A]]].arbitrary.map(v => new ZipStream(v))) - implicit def catsLawsArbitraryForZipNonEmptyVector[A](implicit A: Arbitrary[A]): Arbitrary[ZipNonEmptyVector[A]] = Arbitrary(implicitly[Arbitrary[NonEmptyVector[A]]].arbitrary.map(nev => new ZipNonEmptyVector(nev))) diff --git a/tests/src/test/scala-2.12-/cats/tests/ScalaVersionSpecific.scala b/tests/src/test/scala-2.12-/cats/tests/ScalaVersionSpecific.scala new file mode 100644 index 0000000000..19e61a923f --- /dev/null +++ b/tests/src/test/scala-2.12-/cats/tests/ScalaVersionSpecific.scala @@ -0,0 +1,6 @@ +package cats +package tests + +trait ScalaVersionSpecificFoldableSuite +trait ScalaVersionSpecificParallelSuite +trait ScalaVersionSpecificTraverseSuite diff --git a/tests/src/test/scala/cats/tests/LazyListSuite.scala b/tests/src/test/scala-2.13+/cats/tests/LazyListSuite.scala similarity index 74% rename from tests/src/test/scala/cats/tests/LazyListSuite.scala rename to tests/src/test/scala-2.13+/cats/tests/LazyListSuite.scala index c1581eb7df..5392187a2c 100644 --- a/tests/src/test/scala/cats/tests/LazyListSuite.scala +++ b/tests/src/test/scala-2.13+/cats/tests/LazyListSuite.scala @@ -11,12 +11,9 @@ import cats.laws.discipline.{ TraverseFilterTests, TraverseTests } -import cats.data.ZipStream +import cats.data.ZipLazyList import cats.laws.discipline.arbitrary._ -import kernel.compat.scalaVersionSpecific._ -import compat.lazyList.lazyListString -@suppressUnusedImportWarningForScalaVersionSpecific class LazyListSuite extends CatsSuite { checkAll("LazyList[Int]", SemigroupalTests[LazyList].semigroupal[Int, Int, Int]) checkAll("Semigroupal[LazyList]", SerializableTests.serializable(Semigroupal[LazyList])) @@ -37,21 +34,21 @@ class LazyListSuite extends CatsSuite { checkAll("TraverseFilter[LazyList]", SerializableTests.serializable(TraverseFilter[LazyList])) // Can't test applicative laws as they don't terminate - checkAll("ZipStream[Int]", CommutativeApplyTests[ZipStream].apply[Int, Int, Int]) + checkAll("ZipLazyList[Int]", CommutativeApplyTests[ZipLazyList].apply[Int, Int, Int]) test("show") { - LazyList(1, 2, 3).show should ===(s"$lazyListString(1, ?)") - LazyList.empty[Int].show should ===(s"$lazyListString()") + LazyList(1, 2, 3).show should ===(s"LazyList(1, ?)") + LazyList.empty[Int].show should ===(s"LazyList()") } - test("Show[Stream] is referentially transparent, unlike Stream.toString") { + test("Show[LazyList] is referentially transparent, unlike LazyList.toString") { forAll { lazyList: LazyList[Int] => if (!lazyList.isEmpty) { val unevaluatedLL = lazyList.map(identity) val initialShow = unevaluatedLL.show - // Evaluating the tail can cause Stream.toString to return different values, - // depending on the internal state of the Stream. Show[Stream] should return + // Evaluating the tail can cause LazyList.toString to return different values, + // depending on the internal state of the LazyList. Show[LazyList] should return // consistent values independent of internal state. unevaluatedLL.tail initialShow should ===(unevaluatedLL.show) diff --git a/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala b/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala new file mode 100644 index 0000000000..5323e59414 --- /dev/null +++ b/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala @@ -0,0 +1,142 @@ +package cats +package tests + +import cats.data.{NonEmptyLazyList, ZipLazyList} +import cats.instances.lazyList._ +import cats.laws.discipline.NonEmptyParallelTests +import cats.laws.discipline.arbitrary._ + +trait ScalaVersionSpecificFoldableSuite { self: FoldableSuiteAdditional => + test("Foldable[LazyList].foldM stack safety") { + checkMonadicFoldsStackSafety[LazyList](_.to(LazyList)) + } + + test("Foldable[NonEmptyLazyList].foldM/existsM/forallM/findM/collectFirstSomeM stack safety") { + checkMonadicFoldsStackSafety[NonEmptyLazyList](xs => NonEmptyLazyList(xs.head, xs.tail: _*)) + } + + private def bombLazyList[A]: A = sys.error("boom") + private val dangerousLazyList = 0 #:: 1 #:: 2 #:: bombLazyList[Int] #:: LazyList.empty + private def boomLazyList[A]: LazyList[A] = + bombLazyList[A] #:: LazyList.empty + test("Foldable[LazyList] doesn't blow up") { + + // doesn't blow up - this also ensures it works for infinite streams. + assert(contains(dangerousLazyList, 2).value) + } + + test("Foldable[LazyList] lazy results don't blow up unless you call .value on them") { + contains(dangerousLazyList, -1) + } + + test("Foldable[LazyList] param to foldRight is actually being handled lazily") { + // ensure that the . it only needs to be evaluated if we reach the + // "end" of the fold. + val trap = Eval.later(bombLazyList[Boolean]) + val result = Foldable[LazyList].foldRight(1 #:: 2 #:: LazyList.empty, trap) { (n, lb) => + if (n == 2) Now(true) else lb + } + assert(result.value) + } + + test("Foldable[LazyList] trampolining") { + val large = LazyList((1 to 10000): _*) + assert(contains(large, 10000).value) + } + + test("Foldable[LazyList] laziness of foldM") { + dangerous.foldM(0)((acc, a) => if (a < 2) Some(acc + a) else None) should ===(None) + } + + def foldableLazyListWithDefaultImpl = new Foldable[LazyList] { + def foldLeft[A, B](fa: LazyList[A], b: B)(f: (B, A) => B): B = + Foldable[LazyList].foldLeft(fa, b)(f) + + def foldRight[A, B](fa: LazyList[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + Foldable[LazyList].foldRight(fa, lb)(f) + } + + test(".foldLeftM short-circuiting") { + implicit val F = foldableLazyListWithDefaultImpl + val ns = LazyList.continually(1) + val res = F.foldLeftM[Either[Int, *], Int, Int](ns, 0) { (sum, n) => + if (sum >= 100000) Left(sum) else Right(sum + n) + } + assert(res == Left(100000)) + } + + test(".foldLeftM short-circuiting optimality") { + implicit val F = foldableLazyListWithDefaultImpl + + // test that no more elements are evaluated than absolutely necessary + + def concatUntil(ss: LazyList[String], stop: String): Either[String, String] = + F.foldLeftM[Either[String, *], String, String](ss, "") { (acc, s) => + if (s == stop) Left(acc) else Right(acc + s) + } + + assert(concatUntil("STOP" #:: boomLazyList[String], "STOP") == Left("")) + assert(concatUntil("Zero" #:: "STOP" #:: boomLazyList[String], "STOP") == Left("Zero")) + assert(concatUntil("Zero" #:: "One" #:: "STOP" #:: boomLazyList[String], "STOP") == Left("ZeroOne")) + } + + test(".existsM/.forallM short-circuiting") { + implicit val F = foldableLazyListWithDefaultImpl + assert(F.existsM[Id, Boolean](true #:: boomLazyList[Boolean])(identity) == true) + assert(F.forallM[Id, Boolean](false #:: boomLazyList[Boolean])(identity) == false) + } + + test(".findM/.collectFirstSomeM short-circuiting") { + implicit val F = foldableLazyListWithDefaultImpl + assert((1 #:: boomLazyList[Int]).findM[Id](_ > 0) == Some(1)) + assert((1 #:: boomLazyList[Int]).collectFirstSomeM[Id, Int](Option.apply) == Some(1)) + } +} + +trait ScalaVersionSpecificParallelSuite { self: ParallelSuite => + test("ParMap over LazyList should be consistent with zip") { + forAll { (as: LazyList[Int], bs: LazyList[Int], cs: LazyList[Int]) => + val zipped = as + .zip(bs) + .map { + case (a, b) => a + b + } + .zip(cs) + .map { + case (a, b) => a + b + } + + (as, bs, cs).parMapN(_ + _ + _) should ===(zipped) + } + } + + test("ParTupled of LazyList should be consistent with ParMap of Tuple.apply") { + forAll { (fa: LazyList[Int], fb: LazyList[Int], fc: LazyList[Int], fd: LazyList[Int]) => + (fa, fb, fc, fd).parTupled should ===((fa, fb, fc, fd).parMapN(Tuple4.apply)) + } + } + + test("ParTupled of LazyList should be consistent with zip") { + forAll { (fa: LazyList[Int], fb: LazyList[Int], fc: LazyList[Int], fd: LazyList[Int]) => + (fa, fb, fc, fd).parTupled should ===(fa.zip(fb).zip(fc).zip(fd).map { case (((a, b), c), d) => (a, b, c, d) }) + } + } + + // Can't test Parallel here, as Applicative[ZipLazyList].pure doesn't terminate + checkAll("Parallel[LazyList, ZipLazyList]", + NonEmptyParallelTests[LazyList, ZipLazyList].nonEmptyParallel[Int, String]) + + import NonEmptyLazyList.ZipNonEmptyLazyList + + checkAll("NonEmptyParallel[NonEmptyLazyList, OneAnd[ZipLazyList, *]", + NonEmptyParallelTests[NonEmptyLazyList, ZipNonEmptyLazyList].nonEmptyParallel[Int, String]) +} + +trait ScalaVersionSpecificTraverseSuite { self: TraverseSuiteAdditional => + test("Traverse[LazyList].zipWithIndex stack safety") { + checkZipWithIndexedStackSafety[LazyList](_.to(LazyList)) + } +} + +class TraverseLazyListSuite extends TraverseSuite[LazyList]("LazyList") +class TraverseLazyListSuiteUnderlying extends TraverseSuite.Underlying[LazyList]("LazyList") diff --git a/tests/src/test/scala/cats/tests/BinCodecInvariantMonoidalSuite.scala b/tests/src/test/scala/cats/tests/BinCodecInvariantMonoidalSuite.scala index b14ca1443f..bbbff992f4 100644 --- a/tests/src/test/scala/cats/tests/BinCodecInvariantMonoidalSuite.scala +++ b/tests/src/test/scala/cats/tests/BinCodecInvariantMonoidalSuite.scala @@ -124,7 +124,7 @@ object BinCodecInvariantMonoidalSuite { bitCount <- Gen.oneOf(1, 2, 3) shuffleSeed <- Gen.choose(Long.MinValue, Long.MaxValue) } yield { - val binValues: LazyList[Bin] = LazyList(false, true).replicateA(bitCount).map(MiniList.unsafe(_)) + val binValues: List[Bin] = List(false, true).replicateA(bitCount).map(MiniList.unsafe(_)) val pairs: List[(A, Bin)] = new scala.util.Random(seed = shuffleSeed).shuffle(exA.allValues).toList.zip(binValues) val aToBin: Map[A, Bin] = pairs.toMap val binToA: Map[Bin, A] = pairs.map(_.swap).toMap diff --git a/tests/src/test/scala/cats/tests/FoldableSuite.scala b/tests/src/test/scala/cats/tests/FoldableSuite.scala index 18e195621b..5080fff6ca 100644 --- a/tests/src/test/scala/cats/tests/FoldableSuite.scala +++ b/tests/src/test/scala/cats/tests/FoldableSuite.scala @@ -8,7 +8,6 @@ import cats.instances.all._ import cats.data._ import cats.laws.discipline.arbitrary._ import kernel.compat.scalaVersionSpecific._ -import compat.lazyList.toLazyList @suppressUnusedImportWarningForScalaVersionSpecific abstract class FoldableSuite[F[_]: Foldable](name: String)(implicit ArbFInt: Arbitrary[F[Int]], @@ -238,7 +237,7 @@ abstract class FoldableSuite[F[_]: Foldable](name: String)(implicit ArbFInt: Arb } } -class FoldableSuiteAdditional extends CatsSuite { +class FoldableSuiteAdditional extends CatsSuite with ScalaVersionSpecificFoldableSuite { // exists method written in terms of foldRight def contains[F[_]: Foldable, A: Eq](as: F[A], goal: A): Eval[Boolean] = @@ -338,8 +337,8 @@ class FoldableSuiteAdditional extends CatsSuite { checkMonadicFoldsStackSafety[List](_.toList) } - test("Foldable[LazyList].foldM stack safety") { - checkMonadicFoldsStackSafety[LazyList](toLazyList) + test("Foldable[Stream].foldM stack safety") { + checkMonadicFoldsStackSafety[Stream](_.toStream) } test("Foldable[Vector].foldM/existsM/forallM/findM/collectFirstSomeM stack safety") { @@ -368,51 +367,51 @@ class FoldableSuiteAdditional extends CatsSuite { checkMonadicFoldsStackSafety[NonEmptyStream](xs => NonEmptyStream(xs.head, xs.tail: _*)) } - val F = Foldable[LazyList] + val F = Foldable[Stream] def bomb[A]: A = sys.error("boom") - val dangerous = 0 #:: 1 #:: 2 #:: bomb[Int] #:: LazyList.empty - def boom[A]: LazyList[A] = - bomb[A] #:: LazyList.empty - test("Foldable[LazyList] doesn't blow up") { + val dangerous = 0 #:: 1 #:: 2 #:: bomb[Int] #:: Stream.empty + def boom[A]: Stream[A] = + bomb[A] #:: Stream.empty + test("Foldable[Stream] doesn't blow up") { // doesn't blow up - this also ensures it works for infinite streams. assert(contains(dangerous, 2).value) } - test("Foldable[LazyList] lazy results don't blow up unless you call .value on them") { + test("Foldable[Stream] lazy results don't blow up unless you call .value on them") { contains(dangerous, -1) } - test("Foldable[LazyList] param to foldRight is actually being handled lazily") { + test("Foldable[Stream] param to foldRight is actually being handled lazily") { // ensure that the . it only needs to be evaluated if we reach the // "end" of the fold. val trap = Eval.later(bomb[Boolean]) - val result = F.foldRight(1 #:: 2 #:: LazyList.empty, trap) { (n, lb) => + val result = F.foldRight(1 #:: 2 #:: Stream.empty, trap) { (n, lb) => if (n == 2) Now(true) else lb } assert(result.value) } - test("Foldable[LazyList] trampolining") { - val large = LazyList((1 to 10000): _*) + test("Foldable[Stream] trampolining") { + val large = Stream((1 to 10000): _*) assert(contains(large, 10000).value) } - test("Foldable[LazyList] laziness of foldM") { + test("Foldable[Stream] laziness of foldM") { dangerous.foldM(0)((acc, a) => if (a < 2) Some(acc + a) else None) should ===(None) } - def foldableLazyListWithDefaultImpl = new Foldable[LazyList] { - def foldLeft[A, B](fa: LazyList[A], b: B)(f: (B, A) => B): B = - Foldable[LazyList].foldLeft(fa, b)(f) + def foldableStreamWithDefaultImpl = new Foldable[Stream] { + def foldLeft[A, B](fa: Stream[A], b: B)(f: (B, A) => B): B = + Foldable[Stream].foldLeft(fa, b)(f) - def foldRight[A, B](fa: LazyList[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = - Foldable[LazyList].foldRight(fa, lb)(f) + def foldRight[A, B](fa: Stream[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + Foldable[Stream].foldRight(fa, lb)(f) } test(".foldLeftM short-circuiting") { - implicit val F = foldableLazyListWithDefaultImpl - val ns = LazyList.continually(1) + implicit val F = foldableStreamWithDefaultImpl + val ns = Stream.continually(1) val res = F.foldLeftM[Either[Int, *], Int, Int](ns, 0) { (sum, n) => if (sum >= 100000) Left(sum) else Right(sum + n) } @@ -420,11 +419,11 @@ class FoldableSuiteAdditional extends CatsSuite { } test(".foldLeftM short-circuiting optimality") { - implicit val F = foldableLazyListWithDefaultImpl + implicit val F = foldableStreamWithDefaultImpl // test that no more elements are evaluated than absolutely necessary - def concatUntil(ss: LazyList[String], stop: String): Either[String, String] = + def concatUntil(ss: Stream[String], stop: String): Either[String, String] = F.foldLeftM[Either[String, *], String, String](ss, "") { (acc, s) => if (s == stop) Left(acc) else Right(acc + s) } @@ -435,13 +434,13 @@ class FoldableSuiteAdditional extends CatsSuite { } test(".existsM/.forallM short-circuiting") { - implicit val F = foldableLazyListWithDefaultImpl + implicit val F = foldableStreamWithDefaultImpl assert(F.existsM[Id, Boolean](true #:: boom[Boolean])(identity) == true) assert(F.forallM[Id, Boolean](false #:: boom[Boolean])(identity) == false) } test(".findM/.collectFirstSomeM short-circuiting") { - implicit val F = foldableLazyListWithDefaultImpl + implicit val F = foldableStreamWithDefaultImpl assert((1 #:: boom[Int]).findM[Id](_ > 0) == Some(1)) assert((1 #:: boom[Int]).collectFirstSomeM[Id, Int](Option.apply) == Some(1)) } @@ -465,8 +464,8 @@ class FoldableSortedSetSuite extends FoldableSuite[SortedSet]("sortedSet") { def iterator[T](set: SortedSet[T]): Iterator[T] = set.iterator } -class FoldableLazyListSuite extends FoldableSuite[LazyList]("lazyList") { - def iterator[T](list: LazyList[T]): Iterator[T] = list.iterator +class FoldableStreamSuite extends FoldableSuite[Stream]("lazyList") { + def iterator[T](list: Stream[T]): Iterator[T] = list.iterator } class FoldableSortedMapSuite extends FoldableSuite[SortedMap[Int, *]]("sortedMap") { diff --git a/tests/src/test/scala/cats/tests/ParallelSuite.scala b/tests/src/test/scala/cats/tests/ParallelSuite.scala index a755c510a6..411aee32b5 100644 --- a/tests/src/test/scala/cats/tests/ParallelSuite.scala +++ b/tests/src/test/scala/cats/tests/ParallelSuite.scala @@ -14,7 +14,7 @@ import scala.collection.immutable.SortedSet import kernel.compat.scalaVersionSpecific._ @suppressUnusedImportWarningForScalaVersionSpecific -class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest { +class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest with ScalaVersionSpecificParallelSuite { test("ParSequence Either should accumulate errors") { forAll { es: List[Either[String, Int]] => @@ -303,22 +303,6 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest { } } - test("ParMap over Stream should be consistent with zip") { - forAll { (as: LazyList[Int], bs: LazyList[Int], cs: LazyList[Int]) => - val zipped = as - .zip(bs) - .map { - case (a, b) => a + b - } - .zip(cs) - .map { - case (a, b) => a + b - } - - (as, bs, cs).parMapN(_ + _ + _) should ===(zipped) - } - } - test("ParTupled of NonEmptyList should be consistent with ParMap of Tuple.apply") { forAll { (fa: NonEmptyList[Int], fb: NonEmptyList[Int], fc: NonEmptyList[Int], fd: NonEmptyList[Int]) => (fa, fb, fc, fd).parTupled should ===((fa, fb, fc, fd).parMapN(Tuple4.apply)) @@ -343,12 +327,6 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest { } } - test("ParTupled of Stream should be consistent with ParMap of Tuple.apply") { - forAll { (fa: LazyList[Int], fb: LazyList[Int], fc: LazyList[Int], fd: LazyList[Int]) => - (fa, fb, fc, fd).parTupled should ===((fa, fb, fc, fd).parMapN(Tuple4.apply)) - } - } - test("ParTupled of List should be consistent with zip") { forAll { (fa: List[Int], fb: List[Int], fc: List[Int], fd: List[Int]) => (fa, fb, fc, fd).parTupled should ===(fa.zip(fb).zip(fc).zip(fd).map { case (((a, b), c), d) => (a, b, c, d) }) @@ -361,12 +339,6 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest { } } - test("ParTupled of Stream should be consistent with zip") { - forAll { (fa: LazyList[Int], fb: LazyList[Int], fc: LazyList[Int], fd: LazyList[Int]) => - (fa, fb, fc, fd).parTupled should ===(fa.zip(fb).zip(fc).zip(fd).map { case (((a, b), c), d) => (a, b, c, d) }) - } - } - test("IorT leverages parallel effect instances when it exists") { case class Marker(value: String) extends Exception("marker") { override def fillInStackTrace: Throwable = null @@ -445,8 +417,6 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest { checkAll("NonEmptyParallel[Vector, ZipVector]", NonEmptyParallelTests[Vector, ZipVector].nonEmptyParallel[Int, String]) checkAll("NonEmptyParallel[List, ZipList]", NonEmptyParallelTests[List, ZipList].nonEmptyParallel[Int, String]) - // Can't test Parallel here, as Applicative[ZipStream].pure doesn't terminate - checkAll("Parallel[Stream, ZipStream]", NonEmptyParallelTests[LazyList, ZipStream].nonEmptyParallel[Int, String]) checkAll("NonEmptyParallel[NonEmptyVector, ZipNonEmptyVector]", NonEmptyParallelTests[NonEmptyVector, ZipNonEmptyVector].nonEmptyParallel[Int, String]) diff --git a/tests/src/test/scala/cats/tests/RegressionSuite.scala b/tests/src/test/scala/cats/tests/RegressionSuite.scala index 78eaa80e0e..21389668e1 100644 --- a/tests/src/test/scala/cats/tests/RegressionSuite.scala +++ b/tests/src/test/scala/cats/tests/RegressionSuite.scala @@ -115,7 +115,7 @@ class RegressionSuite extends CatsSuite { // shouldn't have ever evaluted validate(8) checkAndResetCount(3) - LazyList(1, 2, 6, 8).traverse(validate) should ===(Either.left("6 is greater than 5")) + Stream(1, 2, 6, 8).traverse(validate) should ===(Either.left("6 is greater than 5")) checkAndResetCount(3) type StringMap[A] = SortedMap[String, A] @@ -135,7 +135,7 @@ class RegressionSuite extends CatsSuite { List(1, 2, 6, 8).traverse_(validate) should ===(Either.left("6 is greater than 5")) checkAndResetCount(3) - LazyList(1, 2, 6, 8).traverse_(validate) should ===(Either.left("6 is greater than 5")) + Stream(1, 2, 6, 8).traverse_(validate) should ===(Either.left("6 is greater than 5")) checkAndResetCount(3) Vector(1, 2, 6, 8).traverse_(validate) should ===(Either.left("6 is greater than 5")) diff --git a/tests/src/test/scala/cats/tests/StreamSuite.scala b/tests/src/test/scala/cats/tests/StreamSuite.scala new file mode 100644 index 0000000000..e97d92dbbb --- /dev/null +++ b/tests/src/test/scala/cats/tests/StreamSuite.scala @@ -0,0 +1,61 @@ +package cats +package tests + +import cats.laws.discipline.{ + AlternativeTests, + CoflatMapTests, + CommutativeApplyTests, + MonadTests, + SemigroupalTests, + SerializableTests, + TraverseFilterTests, + TraverseTests +} +import cats.data.ZipStream +import cats.laws.discipline.arbitrary._ + +class StreamSuite extends CatsSuite { + checkAll("Stream[Int]", SemigroupalTests[Stream].semigroupal[Int, Int, Int]) + checkAll("Semigroupal[Stream]", SerializableTests.serializable(Semigroupal[Stream])) + + checkAll("Stream[Int]", CoflatMapTests[Stream].coflatMap[Int, Int, Int]) + checkAll("CoflatMap[Stream]", SerializableTests.serializable(CoflatMap[Stream])) + + checkAll("Stream[Int]", AlternativeTests[Stream].alternative[Int, Int, Int]) + checkAll("Alternative[Stream]", SerializableTests.serializable(Alternative[Stream])) + + checkAll("Stream[Int]", MonadTests[Stream].monad[Int, Int, Int]) + checkAll("Monad[Stream]", SerializableTests.serializable(Monad[Stream])) + + checkAll("Stream[Int] with Option", TraverseTests[Stream].traverse[Int, Int, Int, Set[Int], Option, Option]) + checkAll("Traverse[Stream]", SerializableTests.serializable(Traverse[Stream])) + + checkAll("Stream[Int]", TraverseFilterTests[Stream].traverseFilter[Int, Int, Int]) + checkAll("TraverseFilter[Stream]", SerializableTests.serializable(TraverseFilter[Stream])) + + // Can't test applicative laws as they don't terminate + checkAll("ZipStream[Int]", CommutativeApplyTests[ZipStream].apply[Int, Int, Int]) + + test("show") { + Stream(1, 2, 3).show should ===(s"Stream(1, ?)") + Stream.empty[Int].show should ===(s"Stream()") + } + + test("Show[Stream] is referentially transparent, unlike Stream.toString") { + forAll { stream: Stream[Int] => + if (!stream.isEmpty) { + val unevaluatedLL = stream.map(identity) + val initialShow = unevaluatedLL.show + + // Evaluating the tail can cause Stream.toString to return different values, + // depending on the internal state of the Stream. Show[Stream] should return + // consistent values independent of internal state. + unevaluatedLL.tail + initialShow should ===(unevaluatedLL.show) + } else { + stream.show should ===(stream.toString) + } + } + } + +} diff --git a/tests/src/test/scala/cats/tests/TraverseSuite.scala b/tests/src/test/scala/cats/tests/TraverseSuite.scala index d2f65ae8ae..7dbeed6c6a 100644 --- a/tests/src/test/scala/cats/tests/TraverseSuite.scala +++ b/tests/src/test/scala/cats/tests/TraverseSuite.scala @@ -5,7 +5,6 @@ import org.scalacheck.Arbitrary import cats.instances.all._ import kernel.compat.scalaVersionSpecific._ -import compat.lazyList.toLazyList @suppressUnusedImportWarningForScalaVersionSpecific abstract class TraverseSuite[F[_]: Traverse](name: String)(implicit ArbFInt: Arbitrary[F[Int]]) extends CatsSuite { @@ -50,14 +49,14 @@ object TraverseSuite { } class TraverseListSuite extends TraverseSuite[List]("List") -class TraverseStreamSuite extends TraverseSuite[LazyList]("Stream") +class TraverseStreamSuite extends TraverseSuite[Stream]("Stream") class TraverseVectorSuite extends TraverseSuite[Vector]("Vector") class TraverseListSuiteUnderlying extends TraverseSuite.Underlying[List]("List") -class TraverseStreamSuiteUnderlying extends TraverseSuite.Underlying[LazyList]("Stream") +class TraverseStreamSuiteUnderlying extends TraverseSuite.Underlying[Stream]("Stream") class TraverseVectorSuiteUnderlying extends TraverseSuite.Underlying[Vector]("Vector") -class TraverseSuiteAdditional extends CatsSuite { +class TraverseSuiteAdditional extends CatsSuite with ScalaVersionSpecificTraverseSuite { def checkZipWithIndexedStackSafety[F[_]](fromRange: Range => F[Int])(implicit F: Traverse[F]): Unit = { F.zipWithIndex(fromRange(1 to 70000)) @@ -69,7 +68,7 @@ class TraverseSuiteAdditional extends CatsSuite { } test("Traverse[Stream].zipWithIndex stack safety") { - checkZipWithIndexedStackSafety[LazyList](toLazyList) + checkZipWithIndexedStackSafety[Stream](_.toStream) } test("Traverse[Vector].zipWithIndex stack safety") { From 67dc634c37938f87b9c7f97434cb416f76731b89 Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Mon, 19 Aug 2019 12:36:36 -0500 Subject: [PATCH 04/17] Fix duplicate test names --- .../scala-2.13+/cats/tests/ScalaVersionSpecific.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala b/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala index 5323e59414..7ab1a18a3f 100644 --- a/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala +++ b/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala @@ -56,7 +56,7 @@ trait ScalaVersionSpecificFoldableSuite { self: FoldableSuiteAdditional => Foldable[LazyList].foldRight(fa, lb)(f) } - test(".foldLeftM short-circuiting") { + test("Foldable[LazyList].foldLeftM short-circuiting") { implicit val F = foldableLazyListWithDefaultImpl val ns = LazyList.continually(1) val res = F.foldLeftM[Either[Int, *], Int, Int](ns, 0) { (sum, n) => @@ -65,7 +65,7 @@ trait ScalaVersionSpecificFoldableSuite { self: FoldableSuiteAdditional => assert(res == Left(100000)) } - test(".foldLeftM short-circuiting optimality") { + test("Foldable[LazyList].foldLeftM short-circuiting optimality") { implicit val F = foldableLazyListWithDefaultImpl // test that no more elements are evaluated than absolutely necessary @@ -80,13 +80,13 @@ trait ScalaVersionSpecificFoldableSuite { self: FoldableSuiteAdditional => assert(concatUntil("Zero" #:: "One" #:: "STOP" #:: boomLazyList[String], "STOP") == Left("ZeroOne")) } - test(".existsM/.forallM short-circuiting") { + test("Foldable[LazyList].existsM/.forallM short-circuiting") { implicit val F = foldableLazyListWithDefaultImpl assert(F.existsM[Id, Boolean](true #:: boomLazyList[Boolean])(identity) == true) assert(F.forallM[Id, Boolean](false #:: boomLazyList[Boolean])(identity) == false) } - test(".findM/.collectFirstSomeM short-circuiting") { + test("Foldable[LazyList].findM/.collectFirstSomeM short-circuiting") { implicit val F = foldableLazyListWithDefaultImpl assert((1 #:: boomLazyList[Int]).findM[Id](_ > 0) == Some(1)) assert((1 #:: boomLazyList[Int]).collectFirstSomeM[Id, Int](Option.apply) == Some(1)) From 40333b2578e445a560704ff7d037fd0cb0a092b8 Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Tue, 20 Aug 2019 09:38:52 -0500 Subject: [PATCH 05/17] Don't use scalaVersionSpecific helpers in version-specific code --- .../scala-2.12-/cats/data/ScalaVersionSpecificPackage.scala | 3 --- core/src/main/scala-2.12-/cats/data/ZipStream.scala | 5 +---- .../instances/ScalaVersionSpecificParallelInstances.scala | 2 -- .../scala-2.13+/cats/data/ScalaVersionSpecificPackage.scala | 3 --- core/src/main/scala-2.13+/cats/data/ZipStream.scala | 3 --- .../instances/ScalaVersionSpecificParallelInstances.scala | 2 -- .../scala-2.12-/cats/kernel/instances/StreamInstances.scala | 4 +--- .../cats/kernel/instances/LazyListInstances.scala | 2 -- .../scala-2.13+/cats/kernel/instances/StreamInstances.scala | 2 -- 9 files changed, 2 insertions(+), 24 deletions(-) diff --git a/core/src/main/scala-2.12-/cats/data/ScalaVersionSpecificPackage.scala b/core/src/main/scala-2.12-/cats/data/ScalaVersionSpecificPackage.scala index bc11af201a..b088ade790 100644 --- a/core/src/main/scala-2.12-/cats/data/ScalaVersionSpecificPackage.scala +++ b/core/src/main/scala-2.12-/cats/data/ScalaVersionSpecificPackage.scala @@ -1,15 +1,12 @@ package cats package data -import kernel.compat.scalaVersionSpecific._ - abstract private[data] class ScalaVersionSpecificPackage { type NonEmptyStream[A] = OneAnd[Stream, A] def NonEmptyStream[A](head: A, tail: Stream[A] = Stream.empty): NonEmptyStream[A] = OneAnd(head, tail) - @suppressUnusedImportWarningForScalaVersionSpecific def NonEmptyStream[A](head: A, tail: A*): NonEmptyStream[A] = OneAnd(head, tail.toStream) } diff --git a/core/src/main/scala-2.12-/cats/data/ZipStream.scala b/core/src/main/scala-2.12-/cats/data/ZipStream.scala index ca0ecd0e27..0e9a59ea07 100644 --- a/core/src/main/scala-2.12-/cats/data/ZipStream.scala +++ b/core/src/main/scala-2.12-/cats/data/ZipStream.scala @@ -1,11 +1,8 @@ package cats package data -import kernel.compat.scalaVersionSpecific._ - class ZipStream[A](val value: Stream[A]) extends AnyVal -@suppressUnusedImportWarningForScalaVersionSpecific object ZipStream { def apply[A](value: Stream[A]): ZipStream[A] = new ZipStream(value) @@ -18,7 +15,7 @@ object ZipStream { ZipStream(fa.value.map(f)) def ap[A, B](ff: ZipStream[A => B])(fa: ZipStream[A]): ZipStream[B] = - ZipStream(ff.value.lazyZip(fa.value).map(_.apply(_))) + ZipStream((ff.value, fa.value).zipped.map(_.apply(_))) override def product[A, B](fa: ZipStream[A], fb: ZipStream[B]): ZipStream[(A, B)] = ZipStream(fa.value.zip(fb.value)) diff --git a/core/src/main/scala-2.12-/cats/instances/ScalaVersionSpecificParallelInstances.scala b/core/src/main/scala-2.12-/cats/instances/ScalaVersionSpecificParallelInstances.scala index e58f29a725..e572d9c8e9 100644 --- a/core/src/main/scala-2.12-/cats/instances/ScalaVersionSpecificParallelInstances.scala +++ b/core/src/main/scala-2.12-/cats/instances/ScalaVersionSpecificParallelInstances.scala @@ -5,9 +5,7 @@ import cats.data._ import cats.kernel.Semigroup import cats.syntax.either._ import cats.{~>, Applicative, Apply, FlatMap, Functor, Monad, NonEmptyParallel, Parallel} -import kernel.compat.scalaVersionSpecific._ -@suppressUnusedImportWarningForScalaVersionSpecific trait ParallelInstances extends ParallelInstances1 { implicit def catsParallelForEitherValidated[E: Semigroup]: Parallel[Either[E, *], Validated[E, *]] = new Parallel[Either[E, *], Validated[E, *]] { diff --git a/core/src/main/scala-2.13+/cats/data/ScalaVersionSpecificPackage.scala b/core/src/main/scala-2.13+/cats/data/ScalaVersionSpecificPackage.scala index 7a582b21d3..62d97b1a36 100644 --- a/core/src/main/scala-2.13+/cats/data/ScalaVersionSpecificPackage.scala +++ b/core/src/main/scala-2.13+/cats/data/ScalaVersionSpecificPackage.scala @@ -1,8 +1,6 @@ package cats package data -import kernel.compat.scalaVersionSpecific._ - abstract private[data] class ScalaVersionSpecificPackage { type NonEmptyLazyList[+A] = NonEmptyLazyList.Type[A] @deprecated("2.0.0-RC2", "Use NonEmptyLazyList") @@ -12,7 +10,6 @@ abstract private[data] class ScalaVersionSpecificPackage { def NonEmptyStream[A](head: A, tail: Stream[A]): NonEmptyStream[A] = OneAnd(head, tail) - @suppressUnusedImportWarningForScalaVersionSpecific @deprecated("2.0.0-RC2", "Use NonEmptyLazyList") def NonEmptyStream[A](head: A, tail: A*): NonEmptyStream[A] = OneAnd(head, tail.toStream) diff --git a/core/src/main/scala-2.13+/cats/data/ZipStream.scala b/core/src/main/scala-2.13+/cats/data/ZipStream.scala index 3287ec727a..5c90784543 100644 --- a/core/src/main/scala-2.13+/cats/data/ZipStream.scala +++ b/core/src/main/scala-2.13+/cats/data/ZipStream.scala @@ -1,12 +1,9 @@ package cats package data -import kernel.compat.scalaVersionSpecific._ - @deprecated("2.0.0-RC2", "Use ZipLazyList") class ZipStream[A](val value: Stream[A]) extends AnyVal -@suppressUnusedImportWarningForScalaVersionSpecific @deprecated("2.0.0-RC2", "Use ZipLazyList") object ZipStream { diff --git a/core/src/main/scala-2.13+/cats/instances/ScalaVersionSpecificParallelInstances.scala b/core/src/main/scala-2.13+/cats/instances/ScalaVersionSpecificParallelInstances.scala index 3c21117d8f..fd473b00a5 100644 --- a/core/src/main/scala-2.13+/cats/instances/ScalaVersionSpecificParallelInstances.scala +++ b/core/src/main/scala-2.13+/cats/instances/ScalaVersionSpecificParallelInstances.scala @@ -5,9 +5,7 @@ import cats.data._ import cats.kernel.Semigroup import cats.syntax.either._ import cats.{~>, Applicative, Apply, FlatMap, Functor, Monad, NonEmptyParallel, Parallel} -import kernel.compat.scalaVersionSpecific._ -@suppressUnusedImportWarningForScalaVersionSpecific trait ParallelInstances extends ParallelInstances1 { implicit def catsParallelForEitherValidated[E: Semigroup]: Parallel[Either[E, *], Validated[E, *]] = new Parallel[Either[E, *], Validated[E, *]] { diff --git a/kernel/src/main/scala-2.12-/cats/kernel/instances/StreamInstances.scala b/kernel/src/main/scala-2.12-/cats/kernel/instances/StreamInstances.scala index c0e807b58b..d531e4bc61 100644 --- a/kernel/src/main/scala-2.12-/cats/kernel/instances/StreamInstances.scala +++ b/kernel/src/main/scala-2.12-/cats/kernel/instances/StreamInstances.scala @@ -1,8 +1,6 @@ package cats.kernel package instances -import compat.scalaVersionSpecific._ -@suppressUnusedImportWarningForScalaVersionSpecific trait StreamInstances extends StreamInstances1 { implicit def catsKernelStdOrderForStream[A: Order]: Order[Stream[A]] = new StreamOrder[A] @@ -51,6 +49,6 @@ class StreamMonoid[A] extends Monoid[Stream[A]] { override def combineN(x: Stream[A], n: Int): Stream[A] = StaticMethods.combineNIterable(Stream.newBuilder[A], x, n) - override def combineAll(xs: IterableOnce[Stream[A]]): Stream[A] = + override def combineAll(xs: TraversableOnce[Stream[A]]): Stream[A] = StaticMethods.combineAllIterable(Stream.newBuilder[A], xs) } diff --git a/kernel/src/main/scala-2.13+/cats/kernel/instances/LazyListInstances.scala b/kernel/src/main/scala-2.13+/cats/kernel/instances/LazyListInstances.scala index c19d3ad5f7..72c303fa19 100644 --- a/kernel/src/main/scala-2.13+/cats/kernel/instances/LazyListInstances.scala +++ b/kernel/src/main/scala-2.13+/cats/kernel/instances/LazyListInstances.scala @@ -1,8 +1,6 @@ package cats.kernel package instances -import compat.scalaVersionSpecific._ -@suppressUnusedImportWarningForScalaVersionSpecific trait LazyListInstances extends LazyListInstances1 { implicit def catsKernelStdOrderForLazyList[A: Order]: Order[LazyList[A]] = new LazyListOrder[A] diff --git a/kernel/src/main/scala-2.13+/cats/kernel/instances/StreamInstances.scala b/kernel/src/main/scala-2.13+/cats/kernel/instances/StreamInstances.scala index 80f02872bc..06cc3860d1 100644 --- a/kernel/src/main/scala-2.13+/cats/kernel/instances/StreamInstances.scala +++ b/kernel/src/main/scala-2.13+/cats/kernel/instances/StreamInstances.scala @@ -1,8 +1,6 @@ package cats.kernel package instances -import compat.scalaVersionSpecific._ -@suppressUnusedImportWarningForScalaVersionSpecific trait StreamInstances extends StreamInstances1 { @deprecated("2.0.0-RC2", "Use cats.kernel.instances.lazyList") implicit def catsKernelStdOrderForStream[A: Order]: Order[Stream[A]] = From c316ca285182fc9b83f5ad6e0eb754ec064c570f Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Tue, 20 Aug 2019 09:54:41 -0500 Subject: [PATCH 06/17] Add LazyList tests for kernel --- .../kernel/laws/ScalaVersionSpecificTests.scala | 4 ++++ .../kernel/laws/ScalaVersionSpecificTests.scala | 17 +++++++++++++++++ .../test/scala/cats/kernel/laws/LawTests.scala | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 kernel-laws/shared/src/test/scala-2.12-/cats/kernel/laws/ScalaVersionSpecificTests.scala create mode 100644 kernel-laws/shared/src/test/scala-2.13+/cats/kernel/laws/ScalaVersionSpecificTests.scala diff --git a/kernel-laws/shared/src/test/scala-2.12-/cats/kernel/laws/ScalaVersionSpecificTests.scala b/kernel-laws/shared/src/test/scala-2.12-/cats/kernel/laws/ScalaVersionSpecificTests.scala new file mode 100644 index 0000000000..accbd6337b --- /dev/null +++ b/kernel-laws/shared/src/test/scala-2.12-/cats/kernel/laws/ScalaVersionSpecificTests.scala @@ -0,0 +1,4 @@ +package cats.kernel +package laws + +trait ScalaVersionSpecificTests diff --git a/kernel-laws/shared/src/test/scala-2.13+/cats/kernel/laws/ScalaVersionSpecificTests.scala b/kernel-laws/shared/src/test/scala-2.13+/cats/kernel/laws/ScalaVersionSpecificTests.scala new file mode 100644 index 0000000000..dc37dcc085 --- /dev/null +++ b/kernel-laws/shared/src/test/scala-2.13+/cats/kernel/laws/ScalaVersionSpecificTests.scala @@ -0,0 +1,17 @@ +package cats.kernel +package laws + +import cats.kernel.instances.int._ +import cats.kernel.instances.lazyList._ +import cats.kernel.instances.option._ +import cats.kernel.laws.discipline.{EqTests, HashTests, MonoidTests, OrderTests, PartialOrderTests, SerializableTests} + +trait ScalaVersionSpecificTests { this: Tests => + checkAll("Eq[LazyList[HasEq[Int]]]", EqTests[LazyList[HasEq[Int]]].eqv) + checkAll("PartialOrder[LazyList[HasPartialOrder[Int]]]", + PartialOrderTests[LazyList[HasPartialOrder[Int]]].partialOrder) + checkAll("Order[LazyList[Int]]", OrderTests[LazyList[Int]].order) + checkAll("Monoid[LazyList[Int]]", MonoidTests[LazyList[Int]].monoid) + checkAll("Monoid[LazyList[Int]]", SerializableTests.serializable(Monoid[LazyList[Int]])) + checkAll("Hash[LazyList[Int]]", HashTests[LazyList[Int]].hash) +} diff --git a/kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala b/kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala index 5bdcc62ca3..59d0bc2c81 100644 --- a/kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala +++ b/kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala @@ -111,7 +111,7 @@ object KernelCheck { } } -class Tests extends AnyFunSuiteLike with Discipline { +class Tests extends AnyFunSuiteLike with Discipline with ScalaVersionSpecificTests { import KernelCheck._ From 7806c4cf96b7d127748da14a79f934b8957e6aef Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Tue, 20 Aug 2019 10:33:12 -0500 Subject: [PATCH 07/17] Parallel laws checking for NonEmptyLazyList --- .../test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala b/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala index 7ab1a18a3f..7654662c2c 100644 --- a/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala +++ b/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala @@ -3,7 +3,7 @@ package tests import cats.data.{NonEmptyLazyList, ZipLazyList} import cats.instances.lazyList._ -import cats.laws.discipline.NonEmptyParallelTests +import cats.laws.discipline.{ParallelTests, NonEmptyParallelTests} import cats.laws.discipline.arbitrary._ trait ScalaVersionSpecificFoldableSuite { self: FoldableSuiteAdditional => @@ -128,8 +128,8 @@ trait ScalaVersionSpecificParallelSuite { self: ParallelSuite => import NonEmptyLazyList.ZipNonEmptyLazyList - checkAll("NonEmptyParallel[NonEmptyLazyList, OneAnd[ZipLazyList, *]", - NonEmptyParallelTests[NonEmptyLazyList, ZipNonEmptyLazyList].nonEmptyParallel[Int, String]) + checkAll("Parallel[NonEmptyLazyList, ZipNonEmptyLazyList]", + ParallelTests[NonEmptyLazyList, ZipNonEmptyLazyList].parallel[Int, String]) } trait ScalaVersionSpecificTraverseSuite { self: TraverseSuiteAdditional => From e8dcc681258dc6cf0317308e4103c74e9293f5f4 Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Tue, 20 Aug 2019 11:03:13 -0500 Subject: [PATCH 08/17] Provide Parallel instance for NonEmptyLazyList via OneAnd and ZipLazyList --- .../cats/data/NonEmptyLazyList.scala | 45 +++++-------------- .../discipline/ScalaVersionSpecific.scala | 7 --- .../cats/tests/ScalaVersionSpecific.scala | 10 ++--- 3 files changed, 15 insertions(+), 47 deletions(-) diff --git a/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala b/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala index 8e80c4af1e..ab6ec6e3a0 100644 --- a/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala +++ b/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala @@ -51,29 +51,6 @@ object NonEmptyLazyList extends NonEmptyLazyListInstances { implicit def catsNonEmptyLazyListOps[A](value: NonEmptyLazyList[A]): NonEmptyLazyListOps[A] = new NonEmptyLazyListOps(value) - - class ZipNonEmptyLazyList[A](val value: NonEmptyLazyList[A]) extends Serializable - - object ZipNonEmptyLazyList { - - def apply[A](nell: NonEmptyLazyList[A]): ZipNonEmptyLazyList[A] = - new ZipNonEmptyLazyList(nell) - - implicit val catsDataCommutativeApplyForZipNonEmptyLazyList: CommutativeApply[ZipNonEmptyLazyList] = - new CommutativeApply[ZipNonEmptyLazyList] { - def ap[A, B](ff: ZipNonEmptyLazyList[A => B])(fa: ZipNonEmptyLazyList[A]): ZipNonEmptyLazyList[B] = - ZipNonEmptyLazyList(ff.value.zipWith(fa.value)(_.apply(_))) - - override def map[A, B](fa: ZipNonEmptyLazyList[A])(f: (A) => B): ZipNonEmptyLazyList[B] = - ZipNonEmptyLazyList(fa.value.map(f)) - - override def product[A, B](fa: ZipNonEmptyLazyList[A], - fb: ZipNonEmptyLazyList[B]): ZipNonEmptyLazyList[(A, B)] = - ZipNonEmptyLazyList(fa.value.zipWith(fb.value) { case (a, b) => (a, b) }) - } - - implicit def catsDataEqForZipNonEmptyLazyList[A: Eq]: Eq[ZipNonEmptyLazyList[A]] = Eq.by(_.value) - } } class NonEmptyLazyListOps[A](private val value: NonEmptyLazyList[A]) extends AnyVal { @@ -387,21 +364,21 @@ sealed abstract private[data] class NonEmptyLazyListInstances extends NonEmptyLa implicit def catsDataShowForNonEmptyLazyList[A](implicit A: Show[A]): Show[NonEmptyLazyList[A]] = Show.show[NonEmptyLazyList[A]](nell => s"NonEmpty${Show[LazyList[A]].show(nell.toLazyList)}") - import NonEmptyLazyList.ZipNonEmptyLazyList + implicit def catsDataParallelForNonEmptyLazyList: Parallel[NonEmptyLazyList, OneAnd[ZipLazyList, *]] = + new Parallel[NonEmptyLazyList, OneAnd[ZipLazyList, *]] { - implicit def catsDataParallelForNonEmptyLazyList: NonEmptyParallel[NonEmptyLazyList, ZipNonEmptyLazyList] = - new NonEmptyParallel[NonEmptyLazyList, ZipNonEmptyLazyList] { + def applicative: Applicative[OneAnd[ZipLazyList, *]] = + OneAnd.catsDataApplicativeForOneAnd(ZipLazyList.catsDataAlternativeForZipLazyList) + def monad: Monad[NonEmptyLazyList] = NonEmptyLazyList.catsDataInstancesForNonEmptyLazyList - def apply: Apply[ZipNonEmptyLazyList] = ZipNonEmptyLazyList.catsDataCommutativeApplyForZipNonEmptyLazyList - def flatMap: FlatMap[NonEmptyLazyList] = NonEmptyLazyList.catsDataInstancesForNonEmptyLazyList + def sequential: OneAnd[ZipLazyList, *] ~> NonEmptyLazyList = + λ[OneAnd[ZipLazyList, *] ~> NonEmptyLazyList]( + znell => NonEmptyLazyList.fromLazyListPrepend(znell.head, znell.tail.value) + ) - def sequential: ZipNonEmptyLazyList ~> NonEmptyLazyList = - λ[ZipNonEmptyLazyList ~> NonEmptyLazyList](_.value) - - def parallel: NonEmptyLazyList ~> ZipNonEmptyLazyList = - λ[NonEmptyLazyList ~> ZipNonEmptyLazyList](nell => new ZipNonEmptyLazyList(nell)) + def parallel: NonEmptyLazyList ~> OneAnd[ZipLazyList, *] = + λ[NonEmptyLazyList ~> OneAnd[ZipLazyList, *]](nell => OneAnd(nell.head, ZipLazyList(nell.tail))) } - } sealed abstract private[data] class NonEmptyLazyListInstances1 extends NonEmptyLazyListInstances2 { diff --git a/laws/src/main/scala-2.13+/cats/laws/discipline/ScalaVersionSpecific.scala b/laws/src/main/scala-2.13+/cats/laws/discipline/ScalaVersionSpecific.scala index 00ec04c8dc..d37fa27295 100644 --- a/laws/src/main/scala-2.13+/cats/laws/discipline/ScalaVersionSpecific.scala +++ b/laws/src/main/scala-2.13+/cats/laws/discipline/ScalaVersionSpecific.scala @@ -1,7 +1,6 @@ package cats.laws.discipline import cats.data.{NonEmptyLazyList, ZipLazyList, ZipStream} -import cats.data.NonEmptyLazyList.ZipNonEmptyLazyList import org.scalacheck.{Arbitrary, Cogen} private[discipline] object ScalaVersionSpecific { @@ -22,11 +21,5 @@ private[discipline] object ScalaVersionSpecific { implicit def catsLawsCogenForNonEmptyLazyList[A](implicit A: Cogen[A]): Cogen[NonEmptyLazyList[A]] = Cogen[LazyList[A]].contramap(_.toLazyList) - - implicit def catsLawsArbitraryForZipNonEmptyLazyList[A]( - implicit A: Arbitrary[A] - ): Arbitrary[ZipNonEmptyLazyList[A]] = - Arbitrary(implicitly[Arbitrary[NonEmptyLazyList[A]]].arbitrary.map(nev => new ZipNonEmptyLazyList(nev))) - } } diff --git a/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala b/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala index 7654662c2c..8a24054d3f 100644 --- a/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala +++ b/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala @@ -1,9 +1,9 @@ package cats package tests -import cats.data.{NonEmptyLazyList, ZipLazyList} +import cats.data.{NonEmptyLazyList, OneAnd, ZipLazyList} import cats.instances.lazyList._ -import cats.laws.discipline.{ParallelTests, NonEmptyParallelTests} +import cats.laws.discipline.{NonEmptyParallelTests, ParallelTests} import cats.laws.discipline.arbitrary._ trait ScalaVersionSpecificFoldableSuite { self: FoldableSuiteAdditional => @@ -126,10 +126,8 @@ trait ScalaVersionSpecificParallelSuite { self: ParallelSuite => checkAll("Parallel[LazyList, ZipLazyList]", NonEmptyParallelTests[LazyList, ZipLazyList].nonEmptyParallel[Int, String]) - import NonEmptyLazyList.ZipNonEmptyLazyList - - checkAll("Parallel[NonEmptyLazyList, ZipNonEmptyLazyList]", - ParallelTests[NonEmptyLazyList, ZipNonEmptyLazyList].parallel[Int, String]) + checkAll("Parallel[NonEmptyLazyList, OneAnd[ZipLazyList, *]]", + ParallelTests[NonEmptyLazyList, OneAnd[ZipLazyList, *]].parallel[Int, String]) } trait ScalaVersionSpecificTraverseSuite { self: TraverseSuiteAdditional => From 66742d702b5b65addb311580669973db86683595 Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Tue, 20 Aug 2019 11:10:27 -0500 Subject: [PATCH 09/17] Avoid LazyListInstances in non-2.13 code --- .../main/scala-2.12-/cats/instances/all.scala | 52 +++++++++++++++++++ .../scala-2.12-/cats/instances/stream.scala | 5 -- .../cats/instances/all.scala | 0 3 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 core/src/main/scala-2.12-/cats/instances/all.scala rename core/src/main/{scala => scala-2.13+}/cats/instances/all.scala (100%) diff --git a/core/src/main/scala-2.12-/cats/instances/all.scala b/core/src/main/scala-2.12-/cats/instances/all.scala new file mode 100644 index 0000000000..ccc50d259b --- /dev/null +++ b/core/src/main/scala-2.12-/cats/instances/all.scala @@ -0,0 +1,52 @@ +package cats +package instances + +trait AllInstances + extends AnyValInstances + with BigIntInstances + with BigDecimalInstances + with BitSetInstances + with EitherInstances + with EqInstances + with EquivInstances + with FunctionInstances + with FutureInstances + with HashInstances + with InvariantMonoidalInstances + with ListInstances + with MapInstances + with OptionInstances + with OrderInstances + with OrderingInstances + with ParallelInstances + with PartialOrderInstances + with PartialOrderingInstances + with QueueInstances + with SetInstances + with SortedMapInstances + with SortedSetInstances + with StreamInstances + with StringInstances + with SymbolInstances + with TryInstances + with TupleInstances + with UUIDInstances + with VectorInstances + +trait AllInstancesBinCompat0 extends FunctionInstancesBinCompat0 with Tuple2InstancesBinCompat0 + +trait AllInstancesBinCompat1 + extends OptionInstancesBinCompat0 + with ListInstancesBinCompat0 + with VectorInstancesBinCompat0 + with StreamInstancesBinCompat0 + with MapInstancesBinCompat0 + with SortedMapInstancesBinCompat0 + +trait AllInstancesBinCompat2 extends DurationInstances with FiniteDurationInstances + +trait AllInstancesBinCompat3 extends AllCoreDurationInstances + +trait AllInstancesBinCompat4 extends SortedMapInstancesBinCompat1 with MapInstancesBinCompat1 + +trait AllInstancesBinCompat5 extends SortedSetInstancesBinCompat0 diff --git a/core/src/main/scala-2.12-/cats/instances/stream.scala b/core/src/main/scala-2.12-/cats/instances/stream.scala index fea65002be..c93c45312b 100644 --- a/core/src/main/scala-2.12-/cats/instances/stream.scala +++ b/core/src/main/scala-2.12-/cats/instances/stream.scala @@ -5,11 +5,6 @@ import cats.syntax.show._ import scala.annotation.tailrec -/** - * Needed only to avoid some version-specific code in `cats.instances.all`. - */ -private[instances] trait LazyListInstances - trait StreamInstances extends cats.kernel.instances.StreamInstances { implicit val catsStdInstancesForStream diff --git a/core/src/main/scala/cats/instances/all.scala b/core/src/main/scala-2.13+/cats/instances/all.scala similarity index 100% rename from core/src/main/scala/cats/instances/all.scala rename to core/src/main/scala-2.13+/cats/instances/all.scala From bf109816fc1e2996a98c71264c72b2a5d519ae09 Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Wed, 21 Aug 2019 04:42:14 -0500 Subject: [PATCH 10/17] Desperate attempt to fix Travis CI weirdness --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 42562f2f95..830715cadb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -70,7 +70,7 @@ jobs: - &bincompat_check stage: test env: TEST="binary compatibility" - script: sbt ++$TRAVIS_SCALA_VERSION! validateBC + script: sbt ++$TRAVIS_SCALA_VERSION! clean validateBC scala: *scala_version_211 - <<: *bincompat_check scala: *scala_version_212 From ae7b6e57ca78781d96421e13533e791e03a8378b Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Wed, 21 Aug 2019 05:08:27 -0500 Subject: [PATCH 11/17] Revert "Desperate attempt to fix Travis CI weirdness" This reverts commit bf109816fc1e2996a98c71264c72b2a5d519ae09. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 830715cadb..42562f2f95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -70,7 +70,7 @@ jobs: - &bincompat_check stage: test env: TEST="binary compatibility" - script: sbt ++$TRAVIS_SCALA_VERSION! clean validateBC + script: sbt ++$TRAVIS_SCALA_VERSION! validateBC scala: *scala_version_211 - <<: *bincompat_check scala: *scala_version_212 From 9b28588b88f1d9c64710e1bba093adb0703c02ab Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Wed, 21 Aug 2019 05:19:26 -0500 Subject: [PATCH 12/17] Another desperate attempt --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 42562f2f95..c9fa11a84c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -70,7 +70,7 @@ jobs: - &bincompat_check stage: test env: TEST="binary compatibility" - script: sbt ++$TRAVIS_SCALA_VERSION! validateBC + script: sbt ++$TRAVIS_SCALA_VERSION! kernelJVM/compile validateBC scala: *scala_version_211 - <<: *bincompat_check scala: *scala_version_212 From f80d9ab679a8a07d005b0c9676ff7d8b5fed344d Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Wed, 21 Aug 2019 17:07:09 +0200 Subject: [PATCH 13/17] Revert "Another desperate attempt" This reverts commit 9b28588b88f1d9c64710e1bba093adb0703c02ab. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c9fa11a84c..42562f2f95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -70,7 +70,7 @@ jobs: - &bincompat_check stage: test env: TEST="binary compatibility" - script: sbt ++$TRAVIS_SCALA_VERSION! kernelJVM/compile validateBC + script: sbt ++$TRAVIS_SCALA_VERSION! validateBC scala: *scala_version_211 - <<: *bincompat_check scala: *scala_version_212 From fd972c5f5cd634fc417cd0b7f92d770cd9948b97 Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Wed, 21 Aug 2019 17:16:22 +0200 Subject: [PATCH 14/17] Switch to OpenJDK 8 --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 42562f2f95..6c6964ba6d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,15 +2,13 @@ language: scala sudo: required -dist: trusty - group: edge git: depth: 9999 jdk: - - oraclejdk8 + - openjdk8 scala_version_211: &scala_version_211 2.11.12 scala_version_212: &scala_version_212 2.12.9 From 7e52796b5efdcf887445063db14c1a047ff7f581 Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Thu, 22 Aug 2019 09:01:49 +0200 Subject: [PATCH 15/17] Reinstate Stream tests --- .../test/scala/cats/tests/ParallelSuite.scala | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/src/test/scala/cats/tests/ParallelSuite.scala b/tests/src/test/scala/cats/tests/ParallelSuite.scala index 411aee32b5..0077325f2c 100644 --- a/tests/src/test/scala/cats/tests/ParallelSuite.scala +++ b/tests/src/test/scala/cats/tests/ParallelSuite.scala @@ -303,6 +303,22 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest with Sc } } + test("ParMap over Stream should be consistent with zip") { + forAll { (as: LazyList[Int], bs: LazyList[Int], cs: LazyList[Int]) => + val zipped = as + .zip(bs) + .map { + case (a, b) => a + b + } + .zip(cs) + .map { + case (a, b) => a + b + } + + (as, bs, cs).parMapN(_ + _ + _) should ===(zipped) + } + } + test("ParTupled of NonEmptyList should be consistent with ParMap of Tuple.apply") { forAll { (fa: NonEmptyList[Int], fb: NonEmptyList[Int], fc: NonEmptyList[Int], fd: NonEmptyList[Int]) => (fa, fb, fc, fd).parTupled should ===((fa, fb, fc, fd).parMapN(Tuple4.apply)) @@ -327,6 +343,12 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest with Sc } } + test("ParTupled of Stream should be consistent with ParMap of Tuple.apply") { + forAll { (fa: LazyList[Int], fb: LazyList[Int], fc: LazyList[Int], fd: LazyList[Int]) => + (fa, fb, fc, fd).parTupled should ===((fa, fb, fc, fd).parMapN(Tuple4.apply)) + } + } + test("ParTupled of List should be consistent with zip") { forAll { (fa: List[Int], fb: List[Int], fc: List[Int], fd: List[Int]) => (fa, fb, fc, fd).parTupled should ===(fa.zip(fb).zip(fc).zip(fd).map { case (((a, b), c), d) => (a, b, c, d) }) @@ -339,6 +361,12 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest with Sc } } + test("ParTupled of Stream should be consistent with zip") { + forAll { (fa: LazyList[Int], fb: LazyList[Int], fc: LazyList[Int], fd: LazyList[Int]) => + (fa, fb, fc, fd).parTupled should ===(fa.zip(fb).zip(fc).zip(fd).map { case (((a, b), c), d) => (a, b, c, d) }) + } + } + test("IorT leverages parallel effect instances when it exists") { case class Marker(value: String) extends Exception("marker") { override def fillInStackTrace: Throwable = null @@ -417,6 +445,8 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest with Sc checkAll("NonEmptyParallel[Vector, ZipVector]", NonEmptyParallelTests[Vector, ZipVector].nonEmptyParallel[Int, String]) checkAll("NonEmptyParallel[List, ZipList]", NonEmptyParallelTests[List, ZipList].nonEmptyParallel[Int, String]) + // Can't test Parallel here, as Applicative[ZipStream].pure doesn't terminate + checkAll("Parallel[Stream, ZipStream]", NonEmptyParallelTests[LazyList, ZipStream].nonEmptyParallel[Int, String]) checkAll("NonEmptyParallel[NonEmptyVector, ZipNonEmptyVector]", NonEmptyParallelTests[NonEmptyVector, ZipNonEmptyVector].nonEmptyParallel[Int, String]) From a2cdc6b63044dd2198d1d2ac82ebe36b81724381 Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Thu, 22 Aug 2019 09:09:03 +0200 Subject: [PATCH 16/17] ...with the right types this time --- tests/src/test/scala/cats/tests/ParallelSuite.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/src/test/scala/cats/tests/ParallelSuite.scala b/tests/src/test/scala/cats/tests/ParallelSuite.scala index 0077325f2c..ef6cc4f4ff 100644 --- a/tests/src/test/scala/cats/tests/ParallelSuite.scala +++ b/tests/src/test/scala/cats/tests/ParallelSuite.scala @@ -304,7 +304,7 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest with Sc } test("ParMap over Stream should be consistent with zip") { - forAll { (as: LazyList[Int], bs: LazyList[Int], cs: LazyList[Int]) => + forAll { (as: Stream[Int], bs: Stream[Int], cs: Stream[Int]) => val zipped = as .zip(bs) .map { @@ -344,7 +344,7 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest with Sc } test("ParTupled of Stream should be consistent with ParMap of Tuple.apply") { - forAll { (fa: LazyList[Int], fb: LazyList[Int], fc: LazyList[Int], fd: LazyList[Int]) => + forAll { (fa: Stream[Int], fb: Stream[Int], fc: Stream[Int], fd: Stream[Int]) => (fa, fb, fc, fd).parTupled should ===((fa, fb, fc, fd).parMapN(Tuple4.apply)) } } @@ -362,7 +362,7 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest with Sc } test("ParTupled of Stream should be consistent with zip") { - forAll { (fa: LazyList[Int], fb: LazyList[Int], fc: LazyList[Int], fd: LazyList[Int]) => + forAll { (fa: Stream[Int], fb: Stream[Int], fc: Stream[Int], fd: Stream[Int]) => (fa, fb, fc, fd).parTupled should ===(fa.zip(fb).zip(fc).zip(fd).map { case (((a, b), c), d) => (a, b, c, d) }) } } @@ -446,7 +446,7 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest with Sc NonEmptyParallelTests[Vector, ZipVector].nonEmptyParallel[Int, String]) checkAll("NonEmptyParallel[List, ZipList]", NonEmptyParallelTests[List, ZipList].nonEmptyParallel[Int, String]) // Can't test Parallel here, as Applicative[ZipStream].pure doesn't terminate - checkAll("Parallel[Stream, ZipStream]", NonEmptyParallelTests[LazyList, ZipStream].nonEmptyParallel[Int, String]) + checkAll("Parallel[Stream, ZipStream]", NonEmptyParallelTests[Stream, ZipStream].nonEmptyParallel[Int, String]) checkAll("NonEmptyParallel[NonEmptyVector, ZipNonEmptyVector]", NonEmptyParallelTests[NonEmptyVector, ZipNonEmptyVector].nonEmptyParallel[Int, String]) From 6a1c3340dc0f84cbc1e1d7fce3c4dd034aa8c957 Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Thu, 22 Aug 2019 09:17:04 +0200 Subject: [PATCH 17/17] Add regression tests for #513 for LazyList on 2.13 --- .../cats/tests/ScalaVersionSpecific.scala | 1 + .../cats/tests/ScalaVersionSpecific.scala | 22 +++++++++++++++++++ .../scala/cats/tests/RegressionSuite.scala | 2 +- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/src/test/scala-2.12-/cats/tests/ScalaVersionSpecific.scala b/tests/src/test/scala-2.12-/cats/tests/ScalaVersionSpecific.scala index 19e61a923f..ee36a85cbe 100644 --- a/tests/src/test/scala-2.12-/cats/tests/ScalaVersionSpecific.scala +++ b/tests/src/test/scala-2.12-/cats/tests/ScalaVersionSpecific.scala @@ -3,4 +3,5 @@ package tests trait ScalaVersionSpecificFoldableSuite trait ScalaVersionSpecificParallelSuite +trait ScalaVersionSpecificRegressionSuite trait ScalaVersionSpecificTraverseSuite diff --git a/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala b/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala index 8a24054d3f..cfc4ce7437 100644 --- a/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala +++ b/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala @@ -130,6 +130,28 @@ trait ScalaVersionSpecificParallelSuite { self: ParallelSuite => ParallelTests[NonEmptyLazyList, OneAnd[ZipLazyList, *]].parallel[Int, String]) } +trait ScalaVersionSpecificRegressionSuite { self: RegressionSuite => + test("#513: traverse short circuits - Either (for LazyList)") { + var count = 0 + def validate(i: Int): Either[String, Int] = { + count = count + 1 + if (i < 5) Either.right(i) else Either.left(s"$i is greater than 5") + } + + def checkAndResetCount(expected: Int): Unit = { + count should ===(expected) + count = 0 + } + + LazyList(1, 2, 6, 8).traverse(validate) should ===(Either.left("6 is greater than 5")) + // shouldn't have ever evaluted validate(8) + checkAndResetCount(3) + + LazyList(1, 2, 6, 8).traverse_(validate) should ===(Either.left("6 is greater than 5")) + checkAndResetCount(3) + } +} + trait ScalaVersionSpecificTraverseSuite { self: TraverseSuiteAdditional => test("Traverse[LazyList].zipWithIndex stack safety") { checkZipWithIndexedStackSafety[LazyList](_.to(LazyList)) diff --git a/tests/src/test/scala/cats/tests/RegressionSuite.scala b/tests/src/test/scala/cats/tests/RegressionSuite.scala index 21389668e1..ff8d397727 100644 --- a/tests/src/test/scala/cats/tests/RegressionSuite.scala +++ b/tests/src/test/scala/cats/tests/RegressionSuite.scala @@ -7,7 +7,7 @@ import scala.collection.immutable.SortedMap import kernel.compat.scalaVersionSpecific._ @suppressUnusedImportWarningForScalaVersionSpecific -class RegressionSuite extends CatsSuite { +class RegressionSuite extends CatsSuite with ScalaVersionSpecificRegressionSuite { // toy state class // not stack safe, very minimal, not for actual use