All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cats.instances.stream.scala Maven / Gradle / Ivy

The newest version!
package cats
package instances

import cats.data.{Ior, ZipStream}
import cats.syntax.show._

import scala.annotation.tailrec

trait StreamInstances extends cats.kernel.instances.StreamInstances {

  implicit val catsStdInstancesForStream
    : Traverse[Stream] with Alternative[Stream] with Monad[Stream] with CoflatMap[Stream] with Align[Stream] =
    new Traverse[Stream] with Alternative[Stream] with Monad[Stream] with CoflatMap[Stream] with Align[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 toIterable[A](fa: Stream[A]): Iterable[A] = fa

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

      def functor: Functor[Stream] = this

      def align[A, B](fa: Stream[A], fb: Stream[B]): Stream[Ior[A, B]] =
        alignWith(fa, fb)(identity)

      override def alignWith[A, B, C](fa: Stream[A], fb: Stream[B])(f: Ior[A, B] => C): Stream[C] =
        Align.alignWithIterator[A, B, C](fa, fb)(f).toStream
    }

  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}, ?)"
    }

  implicit def catsStdParallelForStreamZipStream: Parallel.Aux[Stream, ZipStream] =
    new Parallel[Stream] {
      type F[x] = ZipStream[x]

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

private[instances] trait StreamInstancesBinCompat0 {
  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 filterNot[A](fa: Stream[A])(f: A => Boolean): Stream[A] = fa.filterNot(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

  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy