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

monocle.Getter.scala Maven / Gradle / Ivy

The newest version!
package monocle

import cats.{Eq, Monoid, Semigroupal}
import cats.arrow.{Arrow, Choice}
import cats.implicits._
import monocle.function.{At, Each, FilterIndex, Index}

/** A [[Getter]] can be seen as a glorified get method between
  * a type S and a type A.
  *
  * A [[Getter]] is also a valid [[Fold]]
  *
  * @tparam S the source of a [[Getter]]
  * @tparam A the target of a [[Getter]]
  */
abstract class Getter[S, A] extends Serializable { self =>

  /** get the target of a [[Getter]] */
  def get(s: S): A

  /** find if the target satisfies the predicate */
  final def find(p: A => Boolean): S => Option[A] =
    s => Some(get(s)).filter(p)

  /** check if the target satisfies the predicate */
  final def exist(p: A => Boolean): S => Boolean =
    p compose get

  /** join two [[Getter]] with the same target */
  final def choice[S1](other: Getter[S1, A]): Getter[Either[S, S1], A] =
    Getter[Either[S, S1], A](_.fold(self.get, other.get))

  /** pair two disjoint [[Getter]] */
  final def split[S1, A1](other: Getter[S1, A1]): Getter[(S, S1), (A, A1)] =
    Getter[(S, S1), (A, A1)] { case (s, s1) => (self.get(s), other.get(s1)) }

  final def zip[A1](other: Getter[S, A1]): Getter[S, (A, A1)] =
    Getter[S, (A, A1)](s => (self.get(s), other.get(s)))

  final def first[B]: Getter[(S, B), (A, B)] =
    Getter[(S, B), (A, B)] { case (s, b) => (self.get(s), b) }

  final def second[B]: Getter[(B, S), (B, A)] =
    Getter[(B, S), (B, A)] { case (b, s) => (b, self.get(s)) }

  final def left[C]: Getter[Either[S, C], Either[A, C]] =
    Getter[Either[S, C], Either[A, C]](_.leftMap(get))

  final def right[C]: Getter[Either[C, S], Either[C, A]] =
    Getter[Either[C, S], Either[C, A]](_.map(get))

  /** Compose with a function lifted into a Getter */
  def to[C](f: A => C): Getter[S, C] =
    andThen(Getter(f))

  def each[C](implicit evEach: Each[A, C]): Fold[S, C] =
    composeTraversal(evEach.each)

  /** Select all the elements which satisfies the predicate.
    * This combinator can break the fusion property see Optional.filter for more details.
    */
  def filter(predicate: A => Boolean): Fold[S, A] =
    self.andThen(Optional.filter(predicate))

  def filterIndex[I, A1](predicate: I => Boolean)(implicit ev: FilterIndex[A, I, A1]): Fold[S, A1] =
    self.andThen(ev.filterIndex(predicate))

  def some[A1](implicit ev1: A =:= Option[A1]): Fold[S, A1] =
    adapt[Option[A1]] composePrism (std.option.pSome)

  def withDefault[A1: Eq](defaultValue: A1)(implicit ev1: A =:= Option[A1]): Getter[S, A1] =
    adapt[Option[A1]] composeIso (std.option.withDefault(defaultValue))

  private def adapt[A1](implicit evA: A =:= A1): Getter[S, A1] =
    evA.substituteCo[Getter[S, *]](this)

  def at[I, A1](i: I)(implicit evAt: At[A, i.type, A1]): Getter[S, A1] =
    andThen(evAt.at(i))

  def index[I, A1](i: I)(implicit evIndex: Index[A, I, A1]): Fold[S, A1] =
    composeOptional(evIndex.index(i))

  /** compose a [[Getter]] with a [[Fold]] */
  final def andThen[B](other: Fold[A, B]): Fold[S, B] =
    asFold.andThen(other)

  /** compose a [[Getter]] with a [[Getter]] */
  final def andThen[B](other: Getter[A, B]): Getter[S, B] =
    (s: S) => other.get(self.get(s))

  /** compose a [[Getter]] with a [[PTraversal]] */
  final def andThen[B, C, D](other: PTraversal[A, B, C, D]): Fold[S, C] =
    asFold.andThen(other)

  /** compose a [[Getter]] with a [[POptional]] */
  final def andThen[B, C, D](other: POptional[A, B, C, D]): Fold[S, C] =
    asFold.andThen(other)

  /** compose a [[Getter]] with a [[PPrism]] */
  final def andThen[B, C, D](other: PPrism[A, B, C, D]): Fold[S, C] =
    asFold.andThen(other)

  /** compose a [[Getter]] with a [[PLens]] */
  final def andThen[B, C, D](other: PLens[A, B, C, D]): Getter[S, C] =
    andThen(other.asGetter)

  /** compose a [[Getter]] with a [[PIso]] */
  final def andThen[B, C, D](other: PIso[A, B, C, D]): Getter[S, C] =
    andThen(other.asGetter)

  /** compose a [[Getter]] with a [[Fold]] */
  @deprecated("use andThen", since = "3.0.0-M1")
  final def composeFold[B](other: Fold[A, B]): Fold[S, B] =
    andThen(other)

  /** compose a [[Getter]] with a [[Getter]] */
  @deprecated("use andThen", since = "3.0.0-M1")
  final def composeGetter[B](other: Getter[A, B]): Getter[S, B] =
    andThen(other)

  /** compose a [[Getter]] with a [[PTraversal]] */
  @deprecated("use andThen", since = "3.0.0-M1")
  final def composeTraversal[B, C, D](other: PTraversal[A, B, C, D]): Fold[S, C] =
    andThen(other)

  /** compose a [[Getter]] with a [[POptional]] */
  @deprecated("use andThen", since = "3.0.0-M1")
  final def composeOptional[B, C, D](other: POptional[A, B, C, D]): Fold[S, C] =
    andThen(other)

  /** compose a [[Getter]] with a [[PPrism]] */
  @deprecated("use andThen", since = "3.0.0-M1")
  final def composePrism[B, C, D](other: PPrism[A, B, C, D]): Fold[S, C] =
    andThen(other)

  /** compose a [[Getter]] with a [[PLens]] */
  @deprecated("use andThen", since = "3.0.0-M1")
  final def composeLens[B, C, D](other: PLens[A, B, C, D]): Getter[S, C] =
    composeGetter(other.asGetter)

  /** compose a [[Getter]] with a [[PIso]] */
  @deprecated("use andThen", since = "3.0.0-M1")
  final def composeIso[B, C, D](other: PIso[A, B, C, D]): Getter[S, C] =
    andThen(other)

  /** *****************************************
    */
  /** Experimental aliases of compose methods */
  /** *****************************************
    */
  /** alias to composeTraversal */
  @deprecated("use andThen", since = "3.0.0-M1")
  final def ^|->>[B, C, D](other: PTraversal[A, B, C, D]): Fold[S, C] =
    andThen(other)

  /** alias to composeOptional */
  @deprecated("use andThen", since = "3.0.0-M1")
  final def ^|-?[B, C, D](other: POptional[A, B, C, D]): Fold[S, C] =
    andThen(other)

  /** alias to composePrism */
  @deprecated("use andThen", since = "3.0.0-M1")
  final def ^<-?[B, C, D](other: PPrism[A, B, C, D]): Fold[S, C] =
    andThen(other)

  /** alias to composeLens */
  @deprecated("use andThen", since = "3.0.0-M1")
  final def ^|->[B, C, D](other: PLens[A, B, C, D]): Getter[S, C] =
    andThen(other)

  /** alias to composeIso */
  @deprecated("use andThen", since = "3.0.0-M1")
  final def ^<->[B, C, D](other: PIso[A, B, C, D]): Getter[S, C] =
    andThen(other)

  /** ***************************************************************
    */
  /** Transformation methods to view a [[Getter]] as another Optics */
  /** ***************************************************************
    */
  /** view a [[Getter]] with a [[Fold]] */
  final def asFold: Fold[S, A] =
    new Fold[S, A] {
      def foldMap[M: Monoid](f: A => M)(s: S): M =
        f(get(s))
    }
}

object Getter extends GetterInstances {
  def id[A]: Getter[A, A] =
    Iso.id[A].asGetter

  def codiagonal[A]: Getter[Either[A, A], A] =
    Getter[Either[A, A], A](_.fold(identity, identity))

  def apply[S, A](_get: S => A): Getter[S, A] =
    (s: S) => _get(s)
}

sealed abstract class GetterInstances extends GetterInstances0 {
  implicit val getterArrow: Arrow[Getter] = new Arrow[Getter] {
    def lift[A, B](f: (A) => B): Getter[A, B] =
      Getter(f)

    def first[A, B, C](f: Getter[A, B]): Getter[(A, C), (B, C)] =
      f.first

    override def second[A, B, C](f: Getter[A, B]): Getter[(C, A), (C, B)] =
      f.second

    override def id[A]: Getter[A, A] =
      Getter.id

    def compose[A, B, C](f: Getter[B, C], g: Getter[A, B]): Getter[A, C] =
      g composeGetter f
  }

  implicit def getterSemigroupal[S]: Semigroupal[Getter[S, *]] =
    new Semigroupal[Getter[S, *]] {
      override def product[A, B](a: Getter[S, A], b: Getter[S, B]) = a zip b
    }
}

sealed abstract class GetterInstances0 {
  implicit val getterChoice: Choice[Getter] = new Choice[Getter] {
    def choice[A, B, C](f: Getter[A, C], g: Getter[B, C]): Getter[Either[A, B], C] =
      f choice g

    def id[A]: Getter[A, A] =
      Getter.id

    def compose[A, B, C](f: Getter[B, C], g: Getter[A, B]): Getter[A, C] =
      g composeGetter f
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy