Skip to content

Commit

Permalink
Add shortcuts for at, index (#978)
Browse files Browse the repository at this point in the history
Co-authored-by: Julien Truffaut <[email protected]>
  • Loading branch information
sapizhak and julien-truffaut authored Dec 6, 2020
1 parent 88e5582 commit 63e08d9
Show file tree
Hide file tree
Showing 25 changed files with 1,399 additions and 22 deletions.
8 changes: 7 additions & 1 deletion core/shared/src/main/scala/monocle/Fold.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import cats.arrow.Choice
import cats.instances.int._
import cats.instances.list._
import cats.syntax.either._
import monocle.function.Each
import monocle.function.{At, Each, Index}
import monocle.internal.Monoids

/** A [[Fold]] can be seen as a [[Getter]] with many targets or
Expand Down Expand Up @@ -100,6 +100,12 @@ abstract class Fold[S, A] extends Serializable { self =>
private def adapt[A1](implicit evA: A =:= A1): Fold[S, A1] =
evA.substituteCo[Fold[S, *]](this)

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

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

/** compose a [[Fold]] with another [[Fold]] */
final def andThen[B](other: Fold[A, B]): Fold[S, B] =
new Fold[S, B] {
Expand Down
8 changes: 7 additions & 1 deletion core/shared/src/main/scala/monocle/Getter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package monocle
import cats.{Eq, Monoid, Semigroupal}
import cats.arrow.{Arrow, Choice}
import cats.implicits._
import monocle.function.Each
import monocle.function.{At, Each, Index}

/** A [[Getter]] can be seen as a glorified get method between
* a type S and a type A.
Expand Down Expand Up @@ -65,6 +65,12 @@ abstract class Getter[S, A] extends Serializable { self =>
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] =
composeLens(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)
Expand Down
8 changes: 7 additions & 1 deletion core/shared/src/main/scala/monocle/Iso.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import cats.{Applicative, Eq, Functor, Monoid}
import cats.arrow.Category
import cats.evidence.{<~<, Is}
import cats.syntax.either._
import monocle.function.Each
import monocle.function.{At, Each, Index}

/** [[Iso]] is a type alias for [[PIso]] where `S` = `A` and `T` = `B`:
* {{{
Expand Down Expand Up @@ -408,4 +408,10 @@ final case class IsoSyntax[S, A](private val self: Iso[S, A]) extends AnyVal {

def withDefault[A1: Eq](defaultValue: A1)(implicit evOpt: A =:= Option[A1]): Iso[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]): Lens[S, A1] =
self composeLens evAt.at(i)

def index[I, A1](i: I)(implicit evIndex: Index[A, I, A1]): Optional[S, A1] =
self composeOptional evIndex.index(i)
}
8 changes: 7 additions & 1 deletion core/shared/src/main/scala/monocle/Lens.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package monocle
import cats.{Applicative, Eq, Functor, Monoid}
import cats.arrow.Choice
import cats.syntax.either._
import monocle.function.Each
import monocle.function.{At, Each, Index}

/** A [[PLens]] can be seen as a pair of functions:
* - `get: S => A` i.e. from an `S`, we can extract an `A`
Expand Down Expand Up @@ -319,4 +319,10 @@ final case class LensSyntax[S, A](private val self: Lens[S, A]) extends AnyVal {

def withDefault[A1: Eq](defaultValue: A1)(implicit evOpt: A =:= Option[A1]): Lens[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]): Lens[S, A1] =
self composeLens evAt.at(i)

def index[I, A1](i: I)(implicit evIndex: Index[A, I, A1]): Optional[S, A1] =
self composeOptional evIndex.index(i)
}
8 changes: 7 additions & 1 deletion core/shared/src/main/scala/monocle/Optional.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package monocle
import cats.{Applicative, Eq, Monoid}
import cats.arrow.Choice
import cats.syntax.either._
import monocle.function.Each
import monocle.function.{At, Each, Index}

/** A [[POptional]] can be seen as a pair of functions:
* - `getOrModify: S => Either[T, A]`
Expand Down Expand Up @@ -335,4 +335,10 @@ final case class OptionalSyntax[S, A](private val self: Optional[S, A]) extends

def withDefault[A1: Eq](defaultValue: A1)(implicit evOpt: A =:= Option[A1]): Optional[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]): Optional[S, A1] =
self composeLens evAt.at(i)

def index[I, A1](i: I)(implicit evIndex: Index[A, I, A1]): Optional[S, A1] =
self composeOptional evIndex.index(i)
}
8 changes: 7 additions & 1 deletion core/shared/src/main/scala/monocle/Prism.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import cats.arrow.Category
import cats.evidence.{<~<, Is}
import cats.instances.option._
import cats.syntax.either._
import monocle.function.Each
import monocle.function.{At, Each, Index}

/** A [[PPrism]] can be seen as a pair of functions:
* - `getOrModify: S => Either[T, A]`
Expand Down Expand Up @@ -374,4 +374,10 @@ final case class PrismSyntax[S, A](private val self: Prism[S, A]) extends AnyVal

def withDefault[A1: Eq](defaultValue: A1)(implicit evOpt: A =:= Option[A1]): Prism[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]): Optional[S, A1] =
self composeLens evAt.at(i)

def index[I, A1](i: I)(implicit evIndex: Index[A, I, A1]): Optional[S, A1] =
self composeOptional evIndex.index(i)
}
8 changes: 7 additions & 1 deletion core/shared/src/main/scala/monocle/Setter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import cats.{Contravariant, Eq, Functor}
import cats.arrow.Choice
import cats.arrow.Profunctor
import cats.syntax.either._
import monocle.function.Each
import monocle.function.{At, Each, Index}

/** A [[PSetter]] is a generalisation of Functor map:
* - `map: (A => B) => F[A] => F[B]`
Expand Down Expand Up @@ -198,4 +198,10 @@ final case class SetterSyntax[S, A](private val self: Setter[S, A]) extends AnyV

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 composeLens evAt.at(i)

def index[I, A1](i: I)(implicit evIndex: Index[A, I, A1]): Setter[S, A1] =
self composeOptional evIndex.index(i)
}
8 changes: 7 additions & 1 deletion core/shared/src/main/scala/monocle/Traversal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import cats.data.Const
import cats.instances.int._
import cats.instances.list._
import cats.syntax.either._
import monocle.function.Each
import monocle.function.{At, Each, Index}
import monocle.internal.Monoids

/** A [[PTraversal]] can be seen as a [[POptional]] generalised to 0 to n targets
Expand Down Expand Up @@ -345,4 +345,10 @@ final case class TraversalSyntax[S, A](private val self: Traversal[S, A]) extend

def withDefault[A1: Eq](defaultValue: A1)(implicit evOpt: A =:= Option[A1]): Traversal[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]): Traversal[S, A1] =
self composeLens evAt.at(i)

def index[I, A1](i: I)(implicit evIndex: Index[A, I, A1]): Traversal[S, A1] =
self composeOptional evIndex.index(i)
}
3 changes: 1 addition & 2 deletions core/shared/src/main/scala/monocle/function/Index.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ object Index extends IndexFunctions {
*/
implicit def listIndex[A]: Index[List[A], Int, A] =
Index(i =>
if (i < 0)
Optional[List[A], A](_ => None)(_ => identity)
if (i < 0) Optional.void
else
Optional[List[A], A](_.drop(i).headOption)(a => s => Try(s.updated(i, a)).getOrElse(s))
)
Expand Down
8 changes: 7 additions & 1 deletion core/shared/src/main/scala/monocle/syntax/ApplyFold.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package monocle.syntax

import cats.{Eq, Monoid}
import monocle.function.Each
import monocle.function.{At, Each, Index}
import monocle.{std, Fold, Getter, PIso, PLens, POptional, PPrism, PTraversal}

case class ApplyFold[S, A](s: S, _fold: Fold[S, A]) {
Expand All @@ -26,6 +26,12 @@ case class ApplyFold[S, A](s: S, _fold: Fold[S, A]) {
def withDefault[A1: Eq](defaultValue: A1)(implicit ev1: A =:= Option[A1]): ApplyFold[S, A1] =
adapt[Option[A1]] composeIso (std.option.withDefault(defaultValue))

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

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

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

Expand Down
8 changes: 7 additions & 1 deletion core/shared/src/main/scala/monocle/syntax/ApplyGetter.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package monocle.syntax

import cats.Eq
import monocle.function.Each
import monocle.function.{At, Each, Index}
import monocle.{std, Fold, Getter, PIso, PLens, POptional, PPrism, PTraversal}

final case class ApplyGetter[S, A](s: S, getter: Getter[S, A]) {
Expand All @@ -18,6 +18,12 @@ final case class ApplyGetter[S, A](s: S, getter: Getter[S, A]) {
def withDefault[A1: Eq](defaultValue: A1)(implicit ev1: A =:= Option[A1]): ApplyGetter[S, A1] =
adapt[Option[A1]] composeIso (std.option.withDefault(defaultValue))

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

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

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

Expand Down
8 changes: 7 additions & 1 deletion core/shared/src/main/scala/monocle/syntax/ApplyIso.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package monocle.syntax

import cats.{Eq, Functor}
import monocle.function.Each
import monocle.function.{At, Each, Index}
import monocle.{std, Fold, Getter, PIso, PLens, POptional, PPrism, PSetter, PTraversal}

final case class ApplyIso[S, T, A, B](s: S, iso: PIso[S, T, A, B]) {
Expand Down Expand Up @@ -75,4 +75,10 @@ final case class ApplyIsoSyntax[S, A](private val self: ApplyIso[S, S, A, A]) ex

def withDefault[A1: Eq](defaultValue: A1)(implicit evOpt: A =:= Option[A1]): ApplyIso[S, S, A1, 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]): ApplyLens[S, S, A1, A1] =
self composeLens evAt.at(i)

def index[I, A1](i: I)(implicit evIndex: Index[A, I, A1]): ApplyOptional[S, S, A1, A1] =
self composeOptional evIndex.index(i)
}
8 changes: 7 additions & 1 deletion core/shared/src/main/scala/monocle/syntax/ApplyLens.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package monocle.syntax

import cats.{Eq, Functor}
import monocle.function.Each
import monocle.function.{At, Each, Index}
import monocle.{std, Fold, Getter, PIso, PLens, POptional, PPrism, PSetter, PTraversal}

final case class ApplyLens[S, T, A, B](s: S, lens: PLens[S, T, A, B]) {
Expand Down Expand Up @@ -76,4 +76,10 @@ final case class ApplyLensSyntax[S, A](private val self: ApplyLens[S, S, A, A])

def withDefault[A1: Eq](defaultValue: A1)(implicit evOpt: A =:= Option[A1]): ApplyLens[S, S, A1, 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]): ApplyLens[S, S, A1, A1] =
self composeLens evAt.at(i)

def index[I, A1](i: I)(implicit evIndex: Index[A, I, A1]): ApplyOptional[S, S, A1, A1] =
self composeOptional evIndex.index(i)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package monocle.syntax

import cats.{Applicative, Eq}
import monocle.function.Each
import monocle.function.{At, Each, Index}
import monocle.{std, Fold, PIso, PLens, POptional, PPrism, PSetter, PTraversal}

final case class ApplyOptional[S, T, A, B](s: S, optional: POptional[S, T, A, B]) {
Expand Down Expand Up @@ -83,4 +83,10 @@ final case class ApplyOptionalSyntax[S, A](private val self: ApplyOptional[S, S,

def withDefault[A1: Eq](defaultValue: A1)(implicit evOpt: A =:= Option[A1]): ApplyOptional[S, S, A1, 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]): ApplyOptional[S, S, A1, A1] =
self composeLens evAt.at(i)

def index[I, A1](i: I)(implicit evIndex: Index[A, I, A1]): ApplyOptional[S, S, A1, A1] =
self composeOptional evIndex.index(i)
}
8 changes: 7 additions & 1 deletion core/shared/src/main/scala/monocle/syntax/ApplyPrism.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package monocle.syntax

import cats.{Applicative, Eq}
import monocle.function.Each
import monocle.function.{At, Each, Index}
import monocle.{std, Fold, PIso, PLens, POptional, PPrism, PSetter, PTraversal}

final case class ApplyPrism[S, T, A, B](s: S, prism: PPrism[S, T, A, B]) {
Expand Down Expand Up @@ -81,4 +81,10 @@ final case class ApplyPrismSyntax[S, A](private val self: ApplyPrism[S, S, A, A]

def withDefault[A1: Eq](defaultValue: A1)(implicit evOpt: A =:= Option[A1]): ApplyPrism[S, S, A1, 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]): ApplyOptional[S, S, A1, A1] =
self composeLens evAt.at(i)

def index[I, A1](i: I)(implicit evIndex: Index[A, I, A1]): ApplyOptional[S, S, A1, A1] =
self composeOptional evIndex.index(i)
}
8 changes: 7 additions & 1 deletion core/shared/src/main/scala/monocle/syntax/ApplySetter.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package monocle.syntax

import cats.Eq
import monocle.function.Each
import monocle.function.{At, Each, Index}
import monocle.{std, PIso, PLens, POptional, PPrism, PSetter, PTraversal}

final case class ApplySetter[S, T, A, B](s: S, setter: PSetter[S, T, A, B]) {
Expand Down Expand Up @@ -66,4 +66,10 @@ final case class ApplySetterSyntax[S, A](private val self: ApplySetter[S, S, A,

def withDefault[A1: Eq](defaultValue: A1)(implicit evOpt: A =:= Option[A1]): ApplySetter[S, S, A1, 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]): ApplySetter[S, S, A1, A1] =
self composeLens evAt.at(i)

def index[I, A1](i: I)(implicit evIndex: Index[A, I, A1]): ApplySetter[S, S, A1, A1] =
self composeOptional evIndex.index(i)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package monocle.syntax

import cats.{Applicative, Eq}
import monocle.function.Each
import monocle.function.{At, Each, Index}
import monocle.{std, Fold, PIso, PLens, POptional, PPrism, PSetter, PTraversal}

final case class ApplyTraversal[S, T, A, B](s: S, traversal: PTraversal[S, T, A, B]) {
Expand Down Expand Up @@ -81,4 +81,10 @@ final case class ApplyTraversalSyntax[S, A](private val self: ApplyTraversal[S,

def withDefault[A1: Eq](defaultValue: A1)(implicit evOpt: A =:= Option[A1]): ApplyTraversal[S, S, A1, 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]): ApplyTraversal[S, S, A1, A1] =
self composeLens evAt.at(i)

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

0 comments on commit 63e08d9

Please sign in to comment.