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

monocle.Setter.scala Maven / Gradle / Ivy

The newest version!
package monocle

import cats.{Contravariant, Eq, Functor}
import cats.arrow.Choice
import cats.arrow.Profunctor
import cats.syntax.either._
import monocle.function.{At, Each, FilterIndex, Index}

/** A [[PSetter]] is a generalisation of Functor map:
  *  - `map:    (A => B) => F[A] => F[B]`
  *  - `modify: (A => B) => S    => T`
  *
  * [[PSetter]] stands for Polymorphic Setter as it replace and modify methods change
  * a type `A` to `B` and `S` to `T`.
  * [[Setter]] is a type alias for [[PSetter]] restricted to monomorphic updates:
  * {{{
  * type Setter[S, A] = PSetter[S, S, A, A]
  * }}}
  *
  * [[PTraversal]], [[POptional]], [[PPrism]], [[PLens]] and [[PIso]] are valid [[PSetter]]
  *
  * @see [[monocle.law.SetterLaws]]
  *
  * @tparam S the source of a [[PSetter]]
  * @tparam T the modified source of a [[PSetter]]
  * @tparam A the target of a [[PSetter]]
  * @tparam B the modified target of a [[PSetter]]
  */
abstract class PSetter[S, T, A, B] extends Serializable { self =>

  /** modify polymorphically the target of a [[PSetter]] with a function */
  def modify(f: A => B): S => T

  /** replace polymorphically the target of a [[PSetter]] with a value */
  def replace(b: B): S => T

  /** alias to replace */
  @deprecated("use replace instead", since = "3.0.0-M1")
  def set(b: B): S => T = replace(b)

  /** join two [[PSetter]] with the same target */
  final def choice[S1, T1](other: PSetter[S1, T1, A, B]): PSetter[Either[S, S1], Either[T, T1], A, B] =
    PSetter[Either[S, S1], Either[T, T1], A, B](b => _.bimap(self.modify(b), other.modify(b)))

  def some[A1, B1](implicit ev1: A =:= Option[A1], ev2: B =:= Option[B1]): PSetter[S, T, A1, B1] =
    adapt[Option[A1], Option[B1]] composePrism (std.option.pSome)

  private[monocle] def adapt[A1, B1](implicit evA: A =:= A1, evB: B =:= B1): PSetter[S, T, A1, B1] =
    evB.substituteCo[PSetter[S, T, A1, *]](evA.substituteCo[PSetter[S, T, *, B]](this))

  /** compose a [[PSetter]] with another [[PSetter]] */
  final def andThen[C, D](other: PSetter[A, B, C, D]): PSetter[S, T, C, D] =
    new PSetter[S, T, C, D] {
      def modify(f: C => D): S => T =
        self.modify(other.modify(f))

      def replace(d: D): S => T =
        self.modify(other.replace(d))
    }

  /** compose a [[PSetter]] with a [[PTraversal]] */
  final def andThen[C, D](other: PTraversal[A, B, C, D]): PSetter[S, T, C, D] =
    andThen(other.asSetter)

  /** compose a [[PSetter]] with a [[POptional]] */
  final def andThen[C, D](other: POptional[A, B, C, D]): PSetter[S, T, C, D] =
    andThen(other.asSetter)

  /** compose a [[PSetter]] with a [[PPrism]] */
  final def andThen[C, D](other: PPrism[A, B, C, D]): PSetter[S, T, C, D] =
    andThen(other.asSetter)

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

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

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

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

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

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

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

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

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

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

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

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

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

object PSetter extends SetterInstances {
  def id[S, T]: PSetter[S, T, S, T] =
    PIso.id[S, T].asSetter

  def codiagonal[S, T]: PSetter[Either[S, S], Either[T, T], S, T] =
    PSetter[Either[S, S], Either[T, T], S, T](f => _.bimap(f, f))

  /** create a [[PSetter]] using modify function */
  def apply[S, T, A, B](_modify: (A => B) => S => T): PSetter[S, T, A, B] =
    new PSetter[S, T, A, B] {
      def modify(f: A => B): S => T =
        _modify(f)

      def replace(b: B): S => T =
        _modify(_ => b)
    }

  /** create a [[PSetter]] from a cats.Functor */
  def fromFunctor[F[_], A, B](implicit F: Functor[F]): PSetter[F[A], F[B], A, B] =
    PSetter[F[A], F[B], A, B](f => F.map(_)(f))

  /** create a [[PSetter]] from a Contravariant functor */
  def fromContravariant[F[_], A, B](implicit F: Contravariant[F]): PSetter[F[B], F[A], A, B] =
    PSetter[F[B], F[A], A, B](f => F.contramap(_)(f))

  /** create a [[PSetter]] from a Profunctor */
  def fromProfunctor[P[_, _], A, B, C](implicit P: Profunctor[P]): PSetter[P[B, C], P[A, C], A, B] =
    PSetter[P[B, C], P[A, C], A, B](f => P.lmap(_)(f))

  implicit def setterSyntax[S, A](self: Setter[S, A]): SetterSyntax[S, A] =
    new SetterSyntax(self)
}

object Setter {
  def id[A]: Setter[A, A] =
    Iso.id[A].asSetter

  def codiagonal[S]: Setter[Either[S, S], S] =
    PSetter.codiagonal

  /** [[Setter]] that points to nothing */
  def void[S, A]: Setter[S, A] =
    Optional.void.asSetter

  /** alias for [[PSetter]] apply with a monomorphic modify function */
  def apply[S, A](modify: (A => A) => S => S): Setter[S, A] =
    PSetter(modify)
}

sealed abstract class SetterInstances {
  implicit val SetterChoice: Choice[Setter] = new Choice[Setter] {
    def compose[A, B, C](f: Setter[B, C], g: Setter[A, B]): Setter[A, C] =
      g composeSetter f

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

    def choice[A, B, C](f1: Setter[A, C], f2: Setter[B, C]): Setter[Either[A, B], C] =
      f1 choice f2
  }
}

/** Extension methods for monomorphic Setter
  */
final case class SetterSyntax[S, A](private val self: Setter[S, A]) extends AnyVal {
  def each[C](implicit evEach: Each[A, C]): Setter[S, C] =
    self 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): Setter[S, A] =
    self.andThen(Optional.filter(predicate))

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

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

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

  def index[I, A1](i: I)(implicit evIndex: Index[A, I, A1]): Setter[S, A1] =
    self.andThen(evIndex.index(i))
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy