Skip to content

Commit

Permalink
add andThen on all optics (#967)
Browse files Browse the repository at this point in the history
  • Loading branch information
julien-truffaut authored Nov 26, 2020
1 parent 42e9ab3 commit 8421493
Show file tree
Hide file tree
Showing 30 changed files with 665 additions and 450 deletions.
64 changes: 44 additions & 20 deletions core/shared/src/main/scala/monocle/Fold.scala
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ abstract class Fold[S, A] extends Serializable { self =>
s.fold(c => f(Either.left(c)), self.foldMap(a => f(Either.right(a))))
}

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

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

Expand All @@ -96,44 +100,64 @@ abstract class Fold[S, A] extends Serializable { self =>
private def adapt[A1](implicit evA: A =:= A1): Fold[S, A1] =
evA.substituteCo[Fold[S, *]](this)

/** *******************************************************
*/
/** Compose methods between a [[Fold]] and another Optics */
/** *******************************************************
*/
/** compose a [[Fold]] with a [[Fold]] */
@inline final def composeFold[B](other: Fold[A, B]): Fold[S, B] =
/** compose a [[Fold]] with another [[Fold]] */
final def andThen[B](other: Fold[A, B]): Fold[S, B] =
new Fold[S, B] {
def foldMap[M: Monoid](f: B => M)(s: S): M =
self.foldMap(other.foldMap(f)(_))(s)
}

/** Compose with a function lifted into a Getter */
@inline def to[C](f: A => C): Fold[S, C] = composeGetter(Getter(f))
/** compose a [[Fold]] with a [[Getter]] */
final def andThen[C](other: Getter[A, C]): Fold[S, C] =
andThen(other.asFold)

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

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

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

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

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

/** compose a [[Fold]] with a [[Fold]] */
@inline final def composeFold[B](other: Fold[A, B]): Fold[S, B] =
andThen(other)

/** compose a [[Fold]] with a [[Getter]] */
@inline final def composeGetter[C](other: Getter[A, C]): Fold[S, C] =
composeFold(other.asFold)
andThen(other.asFold)

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

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

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

/** compose a [[Fold]] with a [[PLens]] */
@inline final def composeLens[B, C, D](other: PLens[A, B, C, D]): Fold[S, C] =
composeFold(other.asFold)
andThen(other.asFold)

/** compose a [[Fold]] with a [[PIso]] */
@inline final def composeIso[B, C, D](other: PIso[A, B, C, D]): Fold[S, C] =
composeFold(other.asFold)
andThen(other.asFold)

/** *****************************************
*/
Expand All @@ -142,23 +166,23 @@ abstract class Fold[S, A] extends Serializable { self =>
*/
/** alias to composeTraversal */
@inline final def ^|->>[B, C, D](other: PTraversal[A, B, C, D]): Fold[S, C] =
composeTraversal(other)
andThen(other)

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

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

/** alias to composeLens */
@inline final def ^|->[B, C, D](other: PLens[A, B, C, D]): Fold[S, C] =
composeLens(other)
andThen(other)

/** alias to composeIso */
@inline final def ^<->[B, C, D](other: PIso[A, B, C, D]): Fold[S, C] =
composeIso(other)
andThen(other)
}

object Fold extends FoldInstances {
Expand Down
62 changes: 43 additions & 19 deletions core/shared/src/main/scala/monocle/Getter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ abstract class Getter[S, A] extends Serializable { self =>
@inline 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)

Expand All @@ -61,41 +65,61 @@ abstract class Getter[S, A] extends Serializable { self =>
private def adapt[A1](implicit evA: A =:= A1): Getter[S, A1] =
evA.substituteCo[Getter[S, *]](this)

/** **********************************************************
*/
/** Compose methods between a [[Getter]] and another Optics */
/** **********************************************************
*/
/** compose a [[Getter]] with a [[Fold]] */
@inline final def composeFold[B](other: Fold[A, B]): Fold[S, B] =
asFold composeFold other
final def andThen[B](other: Fold[A, B]): Fold[S, B] =
asFold.andThen(other)

/** Compose with a function lifted into a Getter */
@inline def to[C](f: A => C): Getter[S, C] = composeGetter(Getter(f))
/** 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]] */
@inline final def composeFold[B](other: Fold[A, B]): Fold[S, B] =
andThen(other)

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

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

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

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

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

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

/** *****************************************
*/
Expand All @@ -104,23 +128,23 @@ abstract class Getter[S, A] extends Serializable { self =>
*/
/** alias to composeTraversal */
@inline final def ^|->>[B, C, D](other: PTraversal[A, B, C, D]): Fold[S, C] =
composeTraversal(other)
andThen(other)

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

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

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

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

/** ***************************************************************
*/
Expand Down
85 changes: 56 additions & 29 deletions core/shared/src/main/scala/monocle/Iso.scala
Original file line number Diff line number Diff line change
Expand Up @@ -110,44 +110,36 @@ abstract class PIso[S, T, A, B] extends Serializable { self =>
private[monocle] def adapt[A1, B1](implicit evA: A =:= A1, evB: B =:= B1): PIso[S, T, A1, B1] =
evB.substituteCo[PIso[S, T, A1, *]](evA.substituteCo[PIso[S, T, *, B]](this))

/** *******************************************************
*/
/** Compose methods between a [[PIso]] and another Optics */
/** *******************************************************
*/
/** compose a [[PIso]] with a [[Fold]] */
@inline final def composeFold[C](other: Fold[A, C]): Fold[S, C] =
asFold composeFold other

/** Compose with a function lifted into a Getter */
@inline def to[C](f: A => C): Getter[S, C] = composeGetter(Getter(f))
final def andThen[C](other: Fold[A, C]): Fold[S, C] =
asFold.andThen(other)

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

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

/** compose a [[PIso]] with a [[PTraversal]] */
@inline final def composeTraversal[C, D](other: PTraversal[A, B, C, D]): PTraversal[S, T, C, D] =
asTraversal composeTraversal other
final def andThen[C, D](other: PTraversal[A, B, C, D]): PTraversal[S, T, C, D] =
asTraversal.andThen(other)

/** compose a [[PIso]] with a [[POptional]] */
@inline final def composeOptional[C, D](other: POptional[A, B, C, D]): POptional[S, T, C, D] =
asOptional composeOptional other
final def andThen[C, D](other: POptional[A, B, C, D]): POptional[S, T, C, D] =
asOptional.andThen(other)

/** compose a [[PIso]] with a [[PPrism]] */
@inline final def composePrism[C, D](other: PPrism[A, B, C, D]): PPrism[S, T, C, D] =
asPrism composePrism other
final def andThen[C, D](other: PPrism[A, B, C, D]): PPrism[S, T, C, D] =
asPrism.andThen(other)

/** compose a [[PIso]] with a [[PLens]] */
@inline final def composeLens[C, D](other: PLens[A, B, C, D]): PLens[S, T, C, D] =
asLens composeLens other
final def andThen[C, D](other: PLens[A, B, C, D]): PLens[S, T, C, D] =
asLens.andThen(other)

/** compose a [[PIso]] with a [[PIso]] */
@inline final def composeIso[C, D](other: PIso[A, B, C, D]): PIso[S, T, C, D] =
/** compose a [[PIso]] with another [[PIso]] */
final def andThen[C, D](other: PIso[A, B, C, D]): PIso[S, T, C, D] =
new PIso[S, T, C, D] { composeSelf =>
def get(s: S): C =
other.get(self.get(s))
Expand All @@ -168,30 +160,65 @@ abstract class PIso[S, T, A, B] extends Serializable { self =>
}
}

/** compose a [[PIso]] with a [[Fold]] */
@inline final def composeFold[C](other: Fold[A, C]): Fold[S, C] =
andThen(other)

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

/** compose a [[PIso]] with a [[Getter]] */
@inline final def composeGetter[C](other: Getter[A, C]): Getter[S, C] =
andThen(other)

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

/** compose a [[PIso]] with a [[PTraversal]] */
@inline final def composeTraversal[C, D](other: PTraversal[A, B, C, D]): PTraversal[S, T, C, D] =
andThen(other)

/** compose a [[PIso]] with a [[POptional]] */
@inline final def composeOptional[C, D](other: POptional[A, B, C, D]): POptional[S, T, C, D] =
andThen(other)

/** compose a [[PIso]] with a [[PPrism]] */
@inline final def composePrism[C, D](other: PPrism[A, B, C, D]): PPrism[S, T, C, D] =
andThen(other)

/** compose a [[PIso]] with a [[PLens]] */
@inline final def composeLens[C, D](other: PLens[A, B, C, D]): PLens[S, T, C, D] =
andThen(other)

/** compose a [[PIso]] with a [[PIso]] */
@inline final def composeIso[C, D](other: PIso[A, B, C, D]): PIso[S, T, C, D] =
andThen(other)

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

/** alias to composeOptional */
@inline final def ^|-?[C, D](other: POptional[A, B, C, D]): POptional[S, T, C, D] =
composeOptional(other)
andThen(other)

/** alias to composePrism */
@inline final def ^<-?[C, D](other: PPrism[A, B, C, D]): PPrism[S, T, C, D] =
composePrism(other)
andThen(other)

/** alias to composeLens */
@inline final def ^|->[C, D](other: PLens[A, B, C, D]): PLens[S, T, C, D] =
composeLens(other)
andThen(other)

/** alias to composeIso */
@inline final def ^<->[C, D](other: PIso[A, B, C, D]): PIso[S, T, C, D] =
composeIso(other)
andThen(other)

/** *************************************************************
*/
Expand Down
Loading

0 comments on commit 8421493

Please sign in to comment.