Skip to content

Commit

Permalink
Merge pull request #2983 from travisbrown/topic/stream-instances
Browse files Browse the repository at this point in the history
Treat Stream and LazyList as different types
  • Loading branch information
travisbrown authored Aug 22, 2019
2 parents 6db5193 + 6a1c334 commit 8c031e5
Show file tree
Hide file tree
Showing 48 changed files with 1,254 additions and 326 deletions.
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
9 changes: 0 additions & 9 deletions core/src/main/scala-2.12-/cats/compat/lazyList.scala

This file was deleted.

26 changes: 26 additions & 0 deletions core/src/main/scala-2.12-/cats/data/OneAndLowPriority4.scala
Original file line number Diff line number Diff line change
@@ -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)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
package cats

package data

abstract private[data] class ScalaVersionSpecificPackage
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)

def NonEmptyStream[A](head: A, tail: A*): NonEmptyStream[A] =
OneAnd(head, tail.toStream)
}
31 changes: 31 additions & 0 deletions core/src/main/scala-2.12-/cats/data/ZipStream.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package cats
package data

class ZipStream[A](val value: Stream[A]) extends AnyVal

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, 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))

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])
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package cats
package instances

import cats.data._
import cats.kernel.Semigroup
import cats.syntax.either._
import cats.{~>, Applicative, Apply, FlatMap, Functor, Monad, NonEmptyParallel, Parallel}

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))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ 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
Expand Down
7 changes: 0 additions & 7 deletions core/src/main/scala-2.12-/cats/instances/stream.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@ import cats.syntax.show._

import scala.annotation.tailrec

/**
* For cross compile with backward compatibility
*/
trait LazyListInstances extends StreamInstances with StreamInstancesBinCompat0 {
val catsStdInstancesForLazyList = catsStdInstancesForStream
}

trait StreamInstances extends cats.kernel.instances.StreamInstances {

implicit val catsStdInstancesForStream
Expand Down
7 changes: 0 additions & 7 deletions core/src/main/scala-2.13+/cats/compat/lazyList.scala

This file was deleted.

17 changes: 16 additions & 1 deletion core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,23 @@ 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)}")

implicit def catsDataParallelForNonEmptyLazyList: Parallel[NonEmptyLazyList, OneAnd[ZipLazyList, *]] =
new Parallel[NonEmptyLazyList, OneAnd[ZipLazyList, *]] {

def applicative: Applicative[OneAnd[ZipLazyList, *]] =
OneAnd.catsDataApplicativeForOneAnd(ZipLazyList.catsDataAlternativeForZipLazyList)
def monad: Monad[NonEmptyLazyList] = NonEmptyLazyList.catsDataInstancesForNonEmptyLazyList

def sequential: OneAnd[ZipLazyList, *] ~> NonEmptyLazyList =
λ[OneAnd[ZipLazyList, *] ~> NonEmptyLazyList](
znell => NonEmptyLazyList.fromLazyListPrepend(znell.head, znell.tail.value)
)

def parallel: NonEmptyLazyList ~> OneAnd[ZipLazyList, *] =
λ[NonEmptyLazyList ~> OneAnd[ZipLazyList, *]](nell => OneAnd(nell.head, ZipLazyList(nell.tail)))
}
}

sealed abstract private[data] class NonEmptyLazyListInstances1 extends NonEmptyLazyListInstances2 {
Expand Down
46 changes: 46 additions & 0 deletions core/src/main/scala-2.13+/cats/data/OneAndLowPriority4.scala
Original file line number Diff line number Diff line change
@@ -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)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
package cats

package data

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)

@deprecated("2.0.0-RC2", "Use NonEmptyLazyList")
def NonEmptyStream[A](head: A, tail: A*): NonEmptyStream[A] =
OneAnd(head, tail.toStream)
}
31 changes: 31 additions & 0 deletions core/src/main/scala-2.13+/cats/data/ZipLazyList.scala
Original file line number Diff line number Diff line change
@@ -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])
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
package cats
package data

import instances.stream._
import kernel.compat.scalaVersionSpecific._
@deprecated("2.0.0-RC2", "Use ZipLazyList")
class ZipStream[A](val value: Stream[A]) extends AnyVal

class ZipStream[A](val value: LazyList[A]) extends AnyVal

@suppressUnusedImportWarningForScalaVersionSpecific
@deprecated("2.0.0-RC2", "Use ZipLazyList")
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))
Expand All @@ -24,11 +22,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(Alternative[LazyList].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(_.value)
implicit def catsDataEqForZipStream[A: Eq]: Eq[ZipStream[A]] =
Eq.by((_: ZipStream[A]).value)(cats.kernel.instances.stream.catsKernelStdEqForStream[A])
}
Loading

0 comments on commit 8c031e5

Please sign in to comment.