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

cats.Functor.scala Maven / Gradle / Ivy

The newest version!
package cats

import simulacrum.{noop, typeclass}

/**
 * Functor.
 *
 * The name is short for "covariant functor".
 *
 * Must obey the laws defined in cats.laws.FunctorLaws.
 */
@typeclass trait Functor[F[_]] extends Invariant[F] { self =>
  def map[A, B](fa: F[A])(f: A => B): F[B]

  override def imap[A, B](fa: F[A])(f: A => B)(g: B => A): F[B] = map(fa)(f)

  // derived methods

  /**
   * Alias for [[map]], since [[map]] can't be injected as syntax if
   * the implementing type already had a built-in `.map` method.
   *
   * Example:
   * {{{
   * scala> import cats.implicits._
   *
   * scala> val m: Map[Int, String] = Map(1 -> "hi", 2 -> "there", 3 -> "you")
   *
   * scala> m.fmap(_ ++ "!")
   * res0: Map[Int,String] = Map(1 -> hi!, 2 -> there!, 3 -> you!)
   * }}}
   */
  final def fmap[A, B](fa: F[A])(f: A => B): F[B] = map(fa)(f)

  /**
   * Lifts natural subtyping covariance of covariant Functors.
   *
   * NOTE: In certain (perhaps contrived) situations that rely on universal
   * equality this can result in a `ClassCastException`, because it is
   * implemented as a type cast. It could be implemented as `map(identity)`, but
   * according to the functor laws, that should be equal to `fa`, and a type
   * cast is often much more performant.
   * See [[https://github.com/typelevel/cats/issues/1080#issuecomment-225892635 this example]]
   * of `widen` creating a `ClassCastException`.
   *
   * Example:
   * {{{
   * scala> import cats.Functor
   * scala> import cats.implicits.catsStdInstancesForOption
   *
   * scala> val s = Some(42)
   * scala> Functor[Option].widen(s)
   * res0: Option[Int] = Some(42)
   * }}}
   */
  def widen[A, B >: A](fa: F[A]): F[B] = fa.asInstanceOf[F[B]]

  /**
   * Lift a function f to operate on Functors
   *
   * Example:
   * {{{
   * scala> import cats.Functor
   * scala> import cats.implicits.catsStdInstancesForOption
   *
   * scala> val o = Option(42)
   * scala> Functor[Option].lift((x: Int) => x + 10)(o)
   * res0: Option[Int] = Some(52)
   * }}}
   */
  def lift[A, B](f: A => B): F[A] => F[B] = map(_)(f)

  /**
   * Empty the fa of the values, preserving the structure
   *
   * Example:
   * {{{
   * scala> import cats.Functor
   * scala> import cats.implicits.catsStdInstancesForList
   *
   * scala> Functor[List].void(List(1,2,3))
   * res0: List[Unit] = List((), (), ())
   * }}}
   */
  def void[A](fa: F[A]): F[Unit] = as(fa, ())

  /**
   * Tuple the values in fa with the result of applying a function
   * with the value
   *
   * Example:
   * {{{
   * scala> import cats.Functor
   * scala> import cats.implicits.catsStdInstancesForOption
   *
   * scala> Functor[Option].fproduct(Option(42))(_.toString)
   * res0: Option[(Int, String)] = Some((42,42))
   * }}}
   */
  def fproduct[A, B](fa: F[A])(f: A => B): F[(A, B)] = map(fa)(a => a -> f(a))

  /**
   * Replaces the `A` value in `F[A]` with the supplied value.
   *
   * Example:
   *
   * {{{
   * scala> import cats.Functor
   * scala> import cats.implicits.catsStdInstancesForList
   *
   * scala> Functor[List].as(List(1,2,3), "hello")
   * res0: List[String] = List(hello, hello, hello)
   * }}}
   */
  def as[A, B](fa: F[A], b: B): F[B] = map(fa)(_ => b)

  /**
   * Tuples the `A` value in `F[A]` with the supplied `B` value, with the `B` value on the left.
   *
   * Example:
   * {{{
   * scala> import scala.collection.immutable.Queue
   * scala> import cats.Functor
   * scala> import cats.implicits.catsStdInstancesForQueue
   *
   * scala> Functor[Queue].tupleLeft(Queue("hello", "world"), 42)
   * res0: scala.collection.immutable.Queue[(Int, String)] = Queue((42,hello), (42,world))
   * }}}
   */
  def tupleLeft[A, B](fa: F[A], b: B): F[(B, A)] = map(fa)(a => (b, a))

  /**
   * Tuples the `A` value in `F[A]` with the supplied `B` value, with the `B` value on the right.
   *
   * Example:
   * {{{
   * scala> import scala.collection.immutable.Queue
   * scala> import cats.Functor
   * scala> import cats.implicits.catsStdInstancesForQueue
   *
   * scala> Functor[Queue].tupleRight(Queue("hello", "world"), 42)
   * res0: scala.collection.immutable.Queue[(String, Int)] = Queue((hello,42), (world,42))
   * }}}
   */
  def tupleRight[A, B](fa: F[A], b: B): F[(A, B)] = map(fa)(a => (a, b))

  /**
   * Un-zips an `F[(A, B)]` consisting of element pairs or Tuple2 into two separate F's tupled.
   *
   * NOTE: Check for effect duplication, possibly memoize before
   *
   * {{{
   * scala> import cats.Functor
   * scala> import cats.implicits.catsStdInstancesForList
   *
   * scala> Functor[List].unzip(List((1,2), (3, 4)))
   * res0: (List[Int], List[Int]) = (List(1, 3),List(2, 4))
   * }}}
   *
   */
  @noop
  def unzip[A, B](fab: F[(A, B)]): (F[A], F[B]) = (map(fab)(_._1), map(fab)(_._2))

  /**
   * Lifts `if` to Functor
   *
   * Example:
   * {{{
   * scala> import cats.Functor
   * scala> import cats.implicits.catsStdInstancesForList
   *
   * scala> Functor[List].ifF(List(true, false, false))(1, 0)
   * res0: List[Int] = List(1, 0, 0)
   * }}}
   */
  def ifF[A](fb: F[Boolean])(ifTrue: => A, ifFalse: => A): F[A] = map(fb)(x => if (x) ifTrue else ifFalse)

  def compose[G[_]: Functor]: Functor[λ[α => F[G[α]]]] =
    new ComposedFunctor[F, G] {
      val F = self
      val G = Functor[G]
    }

  override def composeContravariant[G[_]: Contravariant]: Contravariant[λ[α => F[G[α]]]] =
    new ComposedCovariantContravariant[F, G] {
      val F = self
      val G = Contravariant[G]
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy