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

cats.FlatMap.scala Maven / Gradle / Ivy

The newest version!
package cats

import simulacrum.typeclass
import simulacrum.noop

/**
 * FlatMap type class gives us flatMap, which allows us to have a value
 * in a context (F[A]) and then feed that into a function that takes
 * a normal value and returns a value in a context (A => F[B]).
 *
 * One motivation for separating this out from Monad is that there are
 * situations where we can implement flatMap but not pure.  For example,
 * we can implement map or flatMap that transforms the values of Map[K, *],
 * but we can't implement pure (because we wouldn't know what key to use
 * when instantiating the new Map).
 *
 * @see See [[https://github.com/typelevel/cats/issues/3]] for some discussion.
 *
 * Must obey the laws defined in cats.laws.FlatMapLaws.
 */
@typeclass trait FlatMap[F[_]] extends Apply[F] {
  def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]

  /**
   * "flatten" a nested `F` of `F` structure into a single-layer `F` structure.
   *
   * This is also commonly called `join`.
   *
   * Example:
   * {{{
   * scala> import cats.Eval
   * scala> import cats.implicits._
   *
   * scala> val nested: Eval[Eval[Int]] = Eval.now(Eval.now(3))
   * scala> val flattened: Eval[Int] = nested.flatten
   * scala> flattened.value
   * res0: Int = 3
   * }}}
   */
  def flatten[A](ffa: F[F[A]]): F[A] =
    flatMap(ffa)(fa => fa)

  /**
   * Sequentially compose two actions, discarding any value produced by the first. This variant of
   * [[productR]] also lets you define the evaluation strategy of the second action. For instance
   * you can evaluate it only ''after'' the first action has finished:
   *
   * {{{
   * scala> import cats.Eval
   * scala> import cats.implicits._
   * scala> val fa: Option[Int] = Some(3)
   * scala> def fb: Option[String] = Some("foo")
   * scala> fa.productREval(Eval.later(fb))
   * res0: Option[String] = Some(foo)
   * }}}
   */
  def productREval[A, B](fa: F[A])(fb: Eval[F[B]]): F[B] = flatMap(fa)(_ => fb.value)

  @deprecated("Use productREval instead.", "1.0.0-RC2")
  @noop private[cats] def followedByEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[B] = productREval(fa)(fb)

  /**
   * Sequentially compose two actions, discarding any value produced by the second. This variant of
   * [[productL]] also lets you define the evaluation strategy of the second action. For instance
   * you can evaluate it only ''after'' the first action has finished:
   *
   * {{{
   * scala> import cats.Eval
   * scala> import cats.implicits._
   * scala> var count = 0
   * scala> val fa: Option[Int] = Some(3)
   * scala> def fb: Option[Unit] = Some(count += 1)
   * scala> fa.productLEval(Eval.later(fb))
   * res0: Option[Int] = Some(3)
   * scala> assert(count == 1)
   * scala> none[Int].productLEval(Eval.later(fb))
   * res1: Option[Int] = None
   * scala> assert(count == 1)
   * }}}
   */
  def productLEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[A] = flatMap(fa)(a => map(fb.value)(_ => a))

  @deprecated("Use productLEval instead.", "1.0.0-RC2")
  @noop private[cats] def forEffectEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[A] = productLEval(fa)(fb)

  override def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] =
    flatMap(ff)(f => map(fa)(f))

  override def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] =
    flatMap(fa)(a => map(fb)(b => (a, b)))

  override def ap2[A, B, Z](ff: F[(A, B) => Z])(fa: F[A], fb: F[B]): F[Z] =
    flatMap(fa)(a => flatMap(fb)(b => map(ff)(_(a, b))))

  override def map2[A, B, Z](fa: F[A], fb: F[B])(f: (A, B) => Z): F[Z] =
    flatMap(fa)(a => map(fb)(b => f(a, b)))

  override def productR[A, B](fa: F[A])(fb: F[B]): F[B] =
    flatMap(fa)(_ => fb)

  override def productL[A, B](fa: F[A])(fb: F[B]): F[A] =
    map2(fa, fb)((a, _) => a)

  /**
   * Pair `A` with the result of function application.
   *
   * Example:
   * {{{
   * scala> import cats.implicits._
   * scala> List("12", "34", "56").mproduct(_.toList)
   * res0: List[(String, Char)] = List((12,1), (12,2), (34,3), (34,4), (56,5), (56,6))
   * }}}
   */
  def mproduct[A, B](fa: F[A])(f: A => F[B]): F[(A, B)] =
    flatMap(fa)(a => map(f(a))((a, _)))

  /**
   * `if` lifted into monad.
   */
  def ifM[B](fa: F[Boolean])(ifTrue: => F[B], ifFalse: => F[B]): F[B] =
    flatMap(fa)(if (_) ifTrue else ifFalse)

  /**
   * Keeps calling `f` until a `scala.util.Right[B]` is returned.
   *
   * Based on Phil Freeman's
   * [[http://functorial.com/stack-safety-for-free/index.pdf Stack Safety for Free]].
   *
   * Implementations of this method should use constant stack space relative to `f`.
   */
  def tailRecM[A, B](a: A)(f: A => F[Either[A, B]]): F[B]

  /**
   * Apply a monadic function and discard the result while keeping the effect.
   *
   * {{{
   * scala> import cats._, implicits._
   * scala> Option(1).flatTap(_ => None)
   * res0: Option[Int] = None
   * scala> Option(1).flatTap(_ => Some("123"))
   * res1: Option[Int] = Some(1)
   * scala> def nCats(n: Int) = List.fill(n)("cat")
   * nCats: (n: Int)List[String]
   * scala> List[Int](0).flatTap(nCats)
   * res2: List[Int] = List()
   * scala> List[Int](4).flatTap(nCats)
   * res3: List[Int] = List(4, 4, 4, 4)
   * }}}
   */
  def flatTap[A, B](fa: F[A])(f: A => F[B]): F[A] =
    flatMap(fa)(a => as(f(a), a))

  /**
   * Like an infinite loop of >> calls. This is most useful effect loops
   * that you want to run forever in for instance a server.
   *
   * This will be an infinite loop, or it will return an F[Nothing].
   *
   * Be careful using this.
   * For instance, a List of length k will produce a list of length k^n at iteration
   * n. This means if k = 0, we return an empty list, if k = 1, we loop forever
   * allocating single element lists, but if we have a k > 1, we will allocate
   * exponentially increasing memory and very quickly OOM.
   */
  @noop
  def foreverM[A, B](fa: F[A]): F[B] = {
    // allocate two things once for efficiency.
    val leftUnit = Left(())
    val stepResult: F[Either[Unit, B]] = map(fa)(_ => leftUnit)
    tailRecM(())(_ => stepResult)
  }

  /**
   * iterateForeverM is almost exclusively useful for effect types. For instance,
   * A may be some state, we may take the current state, run some effect to get
   * a new state and repeat.
   */
  @noop
  def iterateForeverM[A, B](a: A)(f: A => F[A]): F[B] =
    tailRecM[A, B](a)(f.andThen { fa =>
      map(fa)(Left(_): Either[A, B])
    })

  /**
   * This repeats an F until we get defined values. This can be useful
   * for polling type operations on State (or RNG) Monads, or in effect
   * monads.
   */
  @noop
  def untilDefinedM[A](foa: F[Option[A]]): F[A] = {
    val leftUnit: Either[Unit, A] = Left(())
    val feither: F[Either[Unit, A]] = map(foa) {
      case None    => leftUnit
      case Some(a) => Right(a)
    }
    tailRecM(())(_ => feither)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy