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

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

The newest version!
package cats
package instances

import cats.syntax.show._
import scala.annotation.tailrec
import scala.collection.immutable.Queue
import scala.util.Try

trait QueueInstances extends cats.kernel.instances.QueueInstances {

  implicit val catsStdInstancesForQueue
    : Traverse[Queue] with Alternative[Queue] with Monad[Queue] with CoflatMap[Queue] =
    new Traverse[Queue] with Alternative[Queue] with Monad[Queue] with CoflatMap[Queue] {
      def empty[A]: Queue[A] = Queue.empty

      def combineK[A](x: Queue[A], y: Queue[A]): Queue[A] = x ++ y

      def pure[A](x: A): Queue[A] = Queue(x)

      override def map[A, B](fa: Queue[A])(f: A => B): Queue[B] =
        fa.map(f)

      def flatMap[A, B](fa: Queue[A])(f: A => Queue[B]): Queue[B] =
        fa.flatMap(f)

      override def map2[A, B, Z](fa: Queue[A], fb: Queue[B])(f: (A, B) => Z): Queue[Z] =
        if (fb.isEmpty) Queue.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: Queue[A], fb: Eval[Queue[B]])(f: (A, B) => Z): Eval[Queue[Z]] =
        if (fa.isEmpty) Eval.now(Queue.empty) // no need to evaluate fb
        else fb.map(fb => map2(fa, fb)(f))

      def tailRecM[A, B](a: A)(f: A => Queue[Either[A, B]]): Queue[B] = {
        val bldr = Queue.newBuilder[B]
        @tailrec def go(lists: List[Queue[Either[A, B]]]): Queue[B] =
          lists match {
            case q :: tail =>
              if (q.isEmpty) go(tail)
              else {
                val (e, es) = q.dequeue
                e match {
                  case Right(b) => bldr += b; go(es :: tail)
                  case Left(a)  => go(f(a) :: es :: tail)
                }
              }
            case Nil =>
              bldr.result
          }
        go(f(a) :: Nil)
      }

      def coflatMap[A, B](fa: Queue[A])(f: Queue[A] => B): Queue[B] = {
        val bldr = Queue.newBuilder[B]
        @tailrec def loop(as: Queue[A]): Queue[B] =
          if (as.isEmpty) bldr.result
          else {
            val (_, rest) = as.dequeue
            bldr += f(as)
            loop(rest)
          }
        loop(fa)
      }

      def foldLeft[A, B](fa: Queue[A], b: B)(f: (B, A) => B): B =
        fa.foldLeft(b)(f)

      def foldRight[A, B](fa: Queue[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = {
        def loop(as: Queue[A]): Eval[B] =
          if (as.isEmpty) lb
          else {
            val (h, t) = as.dequeue
            f(h, Eval.defer(loop(t)))
          }
        Eval.defer(loop(fa))
      }

      override def foldMap[A, B](fa: Queue[A])(f: A => B)(implicit B: Monoid[B]): B =
        B.combineAll(fa.iterator.map(f))

      def traverse[G[_], A, B](fa: Queue[A])(f: A => G[B])(implicit G: Applicative[G]): G[Queue[B]] =
        foldRight[A, G[Queue[B]]](fa, Always(G.pure(Queue.empty))) { (a, lglb) =>
          G.map2Eval(f(a), lglb)(_ +: _)
        }.value

      override def mapWithIndex[A, B](fa: Queue[A])(f: (A, Int) => B): Queue[B] = {
        val b = Queue.newBuilder[B]
        fa.iterator.zipWithIndex.map(ai => f(ai._1, ai._2)).foreach(b += _)
        b.result
      }

      override def zipWithIndex[A](fa: Queue[A]): Queue[(A, Int)] =
        fa.zipWithIndex

      override def get[A](fa: Queue[A])(idx: Long): Option[A] =
        if (idx < 0 || idx > Int.MaxValue) None
        else Try(fa(idx.toInt)).toOption

      override def exists[A](fa: Queue[A])(p: A => Boolean): Boolean =
        fa.exists(p)

      override def forall[A](fa: Queue[A])(p: A => Boolean): Boolean =
        fa.forall(p)

      override def isEmpty[A](fa: Queue[A]): Boolean = fa.isEmpty

      override def foldM[G[_], A, B](fa: Queue[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] = {
        def step(in: (Queue[A], B)): G[Either[(Queue[A], B), B]] = {
          val (xs, b) = in
          if (xs.isEmpty) G.pure(Right(b))
          else {
            val (a, tail) = xs.dequeue
            G.map(f(b, a)) { bnext =>
              Left((tail, bnext))
            }
          }
        }

        G.tailRecM((fa, z))(step)
      }

      override def fold[A](fa: Queue[A])(implicit A: Monoid[A]): A = A.combineAll(fa)

      override def toList[A](fa: Queue[A]): List[A] = fa.toList

      override def reduceLeftOption[A](fa: Queue[A])(f: (A, A) => A): Option[A] =
        fa.reduceLeftOption(f)

      override def find[A](fa: Queue[A])(f: A => Boolean): Option[A] =
        fa.find(f)

      override def filter_[A](fa: Queue[A])(p: A => Boolean): List[A] =
        fa.iterator.filter(p).toList

      override def takeWhile_[A](fa: Queue[A])(p: A => Boolean): List[A] =
        fa.iterator.takeWhile(p).toList

      override def dropWhile_[A](fa: Queue[A])(p: A => Boolean): List[A] =
        fa.iterator.dropWhile(p).toList

      override def algebra[A]: Monoid[Queue[A]] =
        new kernel.instances.QueueMonoid[A]

      override def collectFirst[A, B](fa: Queue[A])(pf: PartialFunction[A, B]): Option[B] = fa.collectFirst(pf)

      override def collectFirstSome[A, B](fa: Queue[A])(f: A => Option[B]): Option[B] =
        fa.collectFirst(Function.unlift(f))
    }

  implicit def catsStdShowForQueue[A: Show]: Show[Queue[A]] =
    new Show[Queue[A]] {
      def show(fa: Queue[A]): String =
        fa.iterator.map(_.show).mkString("Queue(", ", ", ")")
    }

  implicit def catsStdTraverseFilterForQueue: TraverseFilter[Queue] = QueueInstances.catsStdTraverseFilterForQueue
}

private object QueueInstances {
  private val catsStdTraverseFilterForQueue: TraverseFilter[Queue] = new TraverseFilter[Queue] {
    val traverse: Traverse[Queue] = cats.instances.queue.catsStdInstancesForQueue

    override def mapFilter[A, B](fa: Queue[A])(f: (A) => Option[B]): Queue[B] =
      fa.collect(Function.unlift(f))

    override def filter[A](fa: Queue[A])(f: (A) => Boolean): Queue[A] = fa.filter(f)

    override def filterNot[A](fa: Queue[A])(f: A => Boolean): Queue[A] = fa.filterNot(f)

    override def collect[A, B](fa: Queue[A])(f: PartialFunction[A, B]): Queue[B] = fa.collect(f)

    override def flattenOption[A](fa: Queue[Option[A]]): Queue[A] = fa.flatten

    def traverseFilter[G[_], A, B](fa: Queue[A])(f: (A) => G[Option[B]])(implicit G: Applicative[G]): G[Queue[B]] =
      fa.foldRight(Eval.now(G.pure(Queue.empty[B])))(
          (x, xse) => G.map2Eval(f(x), xse)((i, o) => i.fold(o)(_ +: o))
        )
        .value

    override def filterA[G[_], A](fa: Queue[A])(f: (A) => G[Boolean])(implicit G: Applicative[G]): G[Queue[A]] =
      fa.foldRight(Eval.now(G.pure(Queue.empty[A])))(
          (x, xse) => G.map2Eval(f(x), xse)((b, vec) => if (b) x +: vec else vec)
        )
        .value
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy