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

scalaz.Lens.scala Maven / Gradle / Ivy

The newest version!
package scalaz

import Id._
import scala.collection.immutable

/**
 * A Lens Family, offering a purely functional means to access and retrieve
 * a field transitioning from type `B1` to type `B2` in a record simultaneously
 * transitioning from type `A1` to type `A2`.  [[scalaz.Lens]] is a convenient
 * alias for when `A1 === A2`, and `B1 === B2`.
 *
 * The term ''field'' should not be interpreted restrictively to mean a member of a class. For example, a lens
 * family can address membership of a `Set`.
 *
 * @see [[scalaz.PLens]]
 *
 * @tparam A1 The initial type of the record
 * @tparam A2 The final type of the record
 * @tparam B1 The initial type of the field
 * @tparam B2 The final type of the field
 */
sealed abstract class LensFamily[A1, A2, B1, B2] {
  def run(a: A1): IndexedStore[B1, B2, A2]

  def apply(a: A1): IndexedStore[B1, B2, A2] =
    run(a)

  import LensFamily._
  import BijectionT._

  def xmapA[X1, X2](f: A2 => X2)(g: X1 => A1): LensFamily[X1, X2, B1, B2] =
    lensFamily(x => run(g(x)) map f)

  def xmapbA[X, A >: A2 <: A1](b: Bijection[A, X]): LensFamily[X, X, B1, B2] =
    xmapA(b to _)(b from _)

  def xmapB[X1, X2](f: B1 => X1)(g: X2 => B2): LensFamily[A1, A2, X1, X2] =
    lensFamily(a => run(a).xmap(f)(g))

  def xmapbB[X, B >: B1 <: B2](b: Bijection[B, X]): LensFamily[A1, A2, X, X] =
    xmapB(b to _)(b from _)

  def get(a: A1): B1 =
    run(a).pos

  def set(a: A1, b: B2): A2 =
    run(a).put(b)

  def setf[X[_]](a: A1, b: X[B2])(implicit XF: Functor[X]): X[A2] =
    run(a).putf(b)

  def st: State[A1, B1] =
    State(s => (s, get(s)))

  /** Modify the value viewed through the lens */
  def mod(f: B1 => B2, a: A1): A2 =
    run(a).puts(f)

  def =>=(f: B1 => B2): A1 => A2 =
    mod(f, _)

  /** Modify the value viewed through the lens, returning a functor `X` full of results. */
  def modf[X[_]](f: B1 => X[B2], a: A1)(implicit XF: Functor[X]): X[A2] =
    run(a).putsf(f)

  def =>>=[X[_]](f: B1 => X[B2])(implicit XF: Functor[X]): A1 => X[A2] =
    modf(f, _)

  /** Modify the value viewed through the lens, returning a `C` on the side.  */
  def modp[C](f: B1 => (B2, C), a: A1): (A2, C) = {
    val (b, c) = f(get(a))
    (set(a, b), c)
  }

  /** Modify the portion of the state viewed through the lens and return its new value. */
  def mods(f: B1 => B2): IndexedState[A1, A2, B2] =
    IndexedState(a => {
      val c = run(a)
      val b = f(c.pos)
      (c put b, b)
    })

  /** Modify the portion of the state viewed through the lens and return its new value. */
  def %=(f: B1 => B2): IndexedState[A1, A2, B2] =
    mods(f)

  /** Modify the portion of the state viewed through the lens and return its old value.
   * @since 7.0.2
   */
  def modo(f: B1 => B2): IndexedState[A1, A2, B1] =
    IndexedState(a => {
      val c = run(a)
      val o = c.pos
      (c put f(o), o)
    })

  /** Modify the portion of the state viewed through the lens and return its old value. alias for `modo`
   * @since 7.0.2
   */
  def <%=(f: B1 => B2): IndexedState[A1, A2, B1] =
    modo(f)

  /** Set the portion of the state viewed through the lens and return its new value. */
  def assign(b: => B2): IndexedState[A1, A2, B2] =
    mods(_ => b)

  /** Set the portion of the state viewed through the lens and return its new value. */
  def :=(b: => B2): IndexedState[A1, A2, B2] =
    assign(b)

  /** Set the portion of the state viewed through the lens and return its old value.
   * @since 7.0.2
   */
  def assigno(b: => B2): IndexedState[A1, A2, B1] =
    modo(_ => b)

  /** Set the portion of the state viewed through the lens and return its old value. alias for `assigno`
   * @since 7.0.2
   */
  def <:=(b: => B2): IndexedState[A1, A2, B1] =
    assigno(b)

  /** Modify the portion of the state viewed through the lens, but do not return its new value. */
  def mods_(f: B1 => B2): IndexedState[A1, A2, Unit] =
    IndexedState(a =>
      (mod(f, a), ()))

  /** Modify the portion of the state viewed through the lens, but do not return its new value. */
  def %==(f: B1 => B2): IndexedState[A1, A2, Unit] =
    mods_(f)

  /** Contravariantly map a state action through a lens. */
  def lifts[C](s: IndexedState[B1, B2, C]): IndexedState[A1, A2, C] =
    IndexedState(a => modp(s(_), a))

  def %%=[C](s: IndexedState[B1, B2, C]): IndexedState[A1, A2, C] =
    lifts(s)

  /** Map the function `f` over the lens as a state action. */
  def map[C](f: B1 => C): State[A1, C] =
    State(a => (a, f(get(a))))

  /** Map the function `f` over the value under the lens, as a state action. */
  def >-[C](f: B1 => C): State[A1, C] = map(f)

  /** Bind the function `f` over the value under the lens, as a state action. */
  def flatMap[C](f: B1 => IndexedState[A1, A2, C]): IndexedState[A1, A2, C] =
    IndexedState(a => f(get(a))(a))

  /** Bind the function `f` over the value under the lens, as a state action. */
  def >>-[C](f: B1 => IndexedState[A1, A2, C]): IndexedState[A1, A2, C] =
    flatMap[C](f)

  /** Sequence the monadic action of looking through the lens to occur before the state action `f`. */
  def ->>-[C](f: => IndexedState[A1, A2, C]): IndexedState[A1, A2, C] =
    flatMap(_ => f)

  /** Contravariantly mapping the state of a state monad through a lens is a natural transformation */
  def liftsNT: IndexedState[B1, B2, *] ~> IndexedState[A1, A2, *] =
    new (IndexedState[B1, B2, *] ~> IndexedState[A1, A2, *]) {
      def apply[C](s : IndexedState[B1, B2, C]): IndexedState[A1, A2, C] =
        IndexedState[A1, A2, C](a => modp(s(_), a))
    }

  /** Lenses can be composed */
  def compose[C1, C2](that: LensFamily[C1, C2, A1, A2]): LensFamily[C1, C2, B1, B2] =
    lensFamily(c => {
      val (ac, a) = that.run(c).run
      val (ba, b) = run(a).run
      IndexedStore(ac compose ba, b)
    })

  /** alias for `compose` */
  def <=<[C1, C2](that: LensFamily[C1, C2, A1, A2]): LensFamily[C1, C2, B1, B2] = compose(that)

  def andThen[C1, C2](that: LensFamily[B1, B2, C1, C2]): LensFamily[A1, A2, C1, C2] =
    that compose this

  /** alias for `andThen` */
  def >=>[C1, C2](that: LensFamily[B1, B2, C1, C2]): LensFamily[A1, A2, C1, C2] = andThen(that)

  /** Two lenses that view a value of the same type can be joined */
  def sum[C1, C2](that: => LensFamily[C1, C2, B1, B2]): LensFamily[A1 \/ C1, A2 \/ C2, B1, B2] =
    lensFamily{
      case -\/(a) =>
        run(a) map  (\/.left)
      case \/-(c) =>
        that run c map (\/.right)
    }

  /** Alias for `sum` */
  def |||[C1, C2](that: => LensFamily[C1, C2, B1, B2]): LensFamily[A1 \/ C1, A2 \/ C2, B1, B2] = sum(that)

  /** Two disjoint lenses can be paired */
  def product[C1, C2, D1, D2](that: LensFamily[C1, C2, D1, D2]): LensFamily[(A1, C1), (A2, C2), (B1, D1), (B2, D2)] =
    lensFamily {
      case (a, c) => run(a) *** that.run(c)
    }

  /** alias for `product` */
  def ***[C1, C2, D1, D2](that: LensFamily[ C1, C2, D1, D2]): LensFamily[(A1, C1), (A2, C2), (B1, D1), (B2, D2)] = product(that)

  trait LensLaw {
    def identity[A >: A2 <: A1, B >: B1 <: B2](a: A)(implicit A: Equal[A]): Boolean = {
      val c = run(a)
      A.equal(c.put(c.pos: B), a)
    }
    def retention[A >: A2 <: A1, B >: B1 <: B2](a: A, b: B)(implicit B: Equal[B]): Boolean =
      B.equal(run(run(a).put(b): A).pos, b)
    def doubleSet[A >: A2 <: A1, B >: B1 <: B2](a: A, b1: B, b2: B)(implicit A: Equal[A]): Boolean = {
      val r = run(a)
      A.equal(run(r.put(b1): A) put b2, r put b2)
    }
  }

  def lensLaw: LensLaw = new LensLaw {}

  /** A homomorphism of lens categories */
  def partial: PLensFamily[A1, A2, B1, B2] =
    PLensFamily.plensFamily(a => Some(run(a)):Option[IndexedStore[B1, B2, A2]])

  /** alias for `partial` */
  def unary_~ : PLensFamily[A1, A2, B1, B2] =
    partial

}

object LensFamily extends LensInstances with LensFunctions {
  def apply[A1, A2, B1, B2](r: A1 => IndexedStore[B1, B2, A2]): LensFamily[A1, A2, B1, B2] =
    lensFamily(r)
}

trait LensFamilyFunctions {

  def lensFamily[A1, A2, B1, B2](r: A1 => IndexedStore[B1, B2, A2]): LensFamily[A1, A2, B1, B2] = new LensFamily[A1, A2, B1, B2] {
    def run(a: A1): IndexedStore[B1, B2, A2] = r(a)
  }

  def lensFamilyg[A1, A2, B1, B2](set: A1 => B2 => A2, get: A1 => B1): LensFamily[A1, A2, B1, B2] =
    lensFamily(a => IndexedStore(set(a), get(a)))

  def lensFamilyu[A1, A2, B1, B2](set: (A1, B2) => A2, get: A1 => B1): LensFamily[A1, A2, B1, B2] =
    lensFamilyg(set.curried, get)

  /** The identity lens family for a given pair of objects */
  def lensFamilyId[A1, A2]: LensFamily[A1, A2, A1, A2] =
    lensFamily(IndexedStore(identity, _))

  /** A lens family that discards the choice of right or left from disjunction */
  def codiagLensFamily[A1, A2]: LensFamily[A1 \/ A1, A2 \/ A2, A1, A2] =
    lensFamilyId[A1, A2] ||| lensFamilyId[A1, A2]

  /** Polymorphically access the first field of a tuple */
  def firstLensFamily[A1, A2, B]: LensFamily[(A1, B), (A2, B), A1, A2] =
    lensFamily {
      case (a, b) => IndexedStore(x => (x, b), a)
    }

  /** Polymorphically access the second field of a tuple */
  def secondLensFamily[A, B1, B2]: LensFamily[(A, B1), (A, B2), B1, B2] =
    lensFamily {
      case (a, b) => IndexedStore(x => (a, x), b)
    }

  /** Polymorphically access the first field of a tuple */
  def lazyFirstLensFamily[A1, A2, B]: LensFamily[LazyTuple2[A1, B], LazyTuple2[A2, B], A1, A2] =
    lensFamily(z => IndexedStore(x => LazyTuple2(x, z._2), z._1))

  /** Polymorphically access the second field of a tuple */
  def lazySecondLensFamily[A, B1, B2]: LensFamily[LazyTuple2[A, B1], LazyTuple2[A, B2], B1, B2] =
    lensFamily(z => IndexedStore(x => LazyTuple2(z._1, x), z._2))

  def predicateLensFamily[A1, A2]: LensFamily[Store[A1, Boolean], Store[A2, Boolean], (A1 \/ A1), (A2 \/ A2)] =
    lensFamily(q => IndexedStore({
      case -\/(l) => Store(_ => true, l)
      case \/-(r) => Store(_ => false, r)
    }, {
      val x = q.pos
      if(q put x) -\/(x) else \/-(x)
    }))

  def factorLensFamily[A1, A2, B1, B2, C1, C2]: LensFamily[((A1, B1) \/ (A1, C1)), ((A2, B2) \/ (A2, C2)), (A1, B1 \/ C1), (A2, B2 \/ C2)] =
    lensFamily(e => IndexedStore({
      case (a, -\/(b)) => -\/((a, b))
      case (a, \/-(c)) => \/-((a, c))
    }, e match {
      case -\/((a, b)) => (a, -\/(b))
      case \/-((a, c)) => (a, \/-(c))
    }))

  def distributeLensFamily[A1, A2, B1, B2, C1, C2]: LensFamily[(A1, B1 \/ C1), (A2, B2 \/ C2), ((A1, B1) \/ (A1, C1)), ((A2, B2) \/ (A2, C2))] =
    lensFamily {
      case (a, e) => IndexedStore({
        case -\/((aa, bb)) => (aa, -\/(bb))
        case \/-((aa, cc)) => (aa, \/-(cc))
      }, e match {
        case -\/(b) => -\/((a, b))
        case \/-(c) => \/-((a, c))

      })
    }

}

trait LensFunctions extends LensFamilyFunctions {

  def lens[A, B](r: A => Store[B, A]): Lens[A, B] = new Lens[A, B] {
    def run(a: A): Store[B, A] = r(a)
  }

  def lensg[A, B](set: A => B => A, get: A => B): Lens[A, B] =
    lens(a => Store(set(a), get(a)))

  def lensu[A, B](set: (A, B) => A, get: A => B): Lens[A, B] =
    lensg(set.curried, get)

  /** The identity lens for a given object */
  def lensId[A]: Lens[A, A] =
    lens(Store(identity, _))

  /** The trivial lens that can retrieve Unit from anything */
  def trivialLens[A]: Lens[A, Unit] =
    lens[A, Unit](a => Store(_ => a, ()))

  /** A lens that discards the choice of right or left from disjunction */
  def codiagLens[A]: Lens[A \/ A, A] =
    lensId[A] ||| lensId[A]

  /** Access the first field of a tuple */
  def firstLens[A, B]: (A, B) @> A =
    lens {
      case (a, b) => Store(x => (x, b), a)
    }

  /** Access the second field of a tuple */
  def secondLens[A, B]: (A, B) @> B =
    lens {
      case (a, b) => Store(x => (a, x), b)
    }

  /** Access the first field of a tuple */
  def lazyFirstLens[A, B]: LazyTuple2[A, B] @> A =
    lens(z => Store(x => LazyTuple2(x, z._2), z._1))

  /** Access the second field of a tuple */
  def lazySecondLens[A, B]: LazyTuple2[A, B] @> B =
    lens(z => Store(x => LazyTuple2(z._1, x), z._2))

  def nelHeadLens[A]: NonEmptyList[A] @> A =
    lens(l => Store(NonEmptyList.nel(_, l.tail), l.head))

  def nelTailLens[A]: NonEmptyList[A] @> List[A] =
    lens(l => Store(ll => NonEmptyList.nel(l.head, IList.fromList(ll)), l.tail.toList))

  /** Access the value at a particular key of a Map **/
  def mapVLens[K, V](k: K): Map[K, V] @> Option[V] =
    lensg(m => ({
      case None => m - k
      case Some(v) => m.updated(k, v)
    }: Option[V] => Map[K, V]), _ get k)

  /** Access the value at a particular key of a Map.WithDefault */
  def mapWithDefaultLens[K,V](k: K): Map.WithDefault[K,V] @> V =
    lensg(m => v => m.updated(k,v), m => m(k))

  /** Specify whether a value is in a Set */
  def setMembershipLens[A](a: A): Set[A] @> Boolean =
    lensg(s => b => if (b) s + a else s - a, _.contains(a))

  def applyLens[A, B](k: B => A)(implicit e: Equal[A]): Store[A, B] @> B =
    lens(q => {
      val x = Need(q.pos)
      val y = Need(q put x.value)
      Store(b =>
        Store(w => if(e.equal(x.value, w)) b else y.value, x.value), y.value)
    })

  def predicateLens[A]: Store[A, Boolean] @> (A \/ A) =
    lens(q => Store({
      case -\/(l) => Store(_ => true, l)
      case \/-(r) => Store(_ => false, r)
    }, {
      val x = q.pos
      if(q put x) -\/(x) else \/-(x)
    }))

  def factorLens[A, B, C]: ((A, B) \/ (A, C)) @> (A, B \/ C) =
    lens(e => Store({
      case (a, -\/(b)) => -\/((a, b))
      case (a, \/-(c)) => \/-((a, c))
    }, e match {
      case -\/((a, b)) => (a, -\/(b))
      case \/-((a, c)) => (a, \/-(c))
    }))

  def distributeLens[A, B, C]: (A, B \/ C) @> ((A, B) \/ (A, C)) =
    lens {
      case (a, e) => Store({
        case -\/((aa, bb)) => (aa, -\/(bb))
        case \/-((aa, cc)) => (aa, \/-(cc))
      }, e match {
        case -\/(b) => -\/((a, b))
        case \/-(c) => \/-((a, c))

      })
    }
}

sealed abstract class LensInstances0 { this: LensInstances =>
  import scala.collection.SeqLike

  implicit def seqLikeLensFamily[S1, S2, A, Repr <: SeqLike[A, Repr]](lens: LensFamily[S1, S2, Repr, Repr]): SeqLikeLensFamily[S1, S2, A, Repr] =
    SeqLikeLens[S1, S2, A, Repr](lens)

}

abstract class LensInstances extends LensInstances0 {
  import LensFamily._
  import BijectionT._
  import scala.collection.SeqLike
  import scala.collection.immutable.Queue

  implicit val lensCategory: LensCategory = new LensCategory {
  }

  /** Lenses may be used implicitly as State monadic actions that get the viewed portion of the state */
  implicit def LensFamilyState[A, B](lens: LensFamily[A, _, B, _]): State[A, B] =
    lens.st

  implicit def LensFamilyUnzip[S, R]: Unzip[λ[α => LensFamily[S, R, α, α]]] =
    new Unzip[λ[α => LensFamily[S, R, α, α]]] {
      def unzip[A, B](a: LensFamily[S, R, (A, B), (A, B)]) =
        (
          lensFamily(x => {
            val c = a run x
            val (p, q) = c.pos
            IndexedStore(a => c.put((a, q)): R, p)
          })
        , lensFamily(x => {
          val c = a run x
          val (p, q) = c.pos
          IndexedStore(a => c.put((p, a)): R, q)
        })
        )
    }

  type SetLens[S, K] = SetLensFamily[S, S, K]
  val SetLens: SetLensFamily.type = SetLensFamily
  case class SetLensFamily[S1, S2, K](lens: LensFamily[S1, S2, Set[K], Set[K]]) {
    /** Setting the value of this lens will change whether or not it is present in the set */
    def contains(key: K): LensFamily[S1, S2, Boolean, Boolean] = lensFamilyg[S1, S2, Boolean, Boolean](
      s => b => lens.mod(m => if (b) m + key else m - key, s): Id[S2]
    , s => lens.get(s).contains(key)
    )

    def &=(that: Set[K]): IndexedState[S1, S2, Set[K]] =
      lens %= (_ & that)

    def &~=(that: Set[K]): IndexedState[S1, S2, Set[K]] =
      lens %= (_ &~ that)

    def |=(that: Set[K]): IndexedState[S1, S2, Set[K]] =
      lens %= (_ | that)

    def +=(elem: K): IndexedState[S1, S2, Set[K]] =
      lens %= (_ + elem)

    def +=(elem1: K, elem2: K, elems: K*): IndexedState[S1, S2, Set[K]] =
      lens %= (_ + elem1 + elem2 ++ elems)

    def ++=(xs: IterableOnce[K]): IndexedState[S1, S2, Set[K]] =
      lens %= (_ ++ xs)

    def -=(elem: K): IndexedState[S1, S2, Set[K]] =
      lens %= (_ - elem)

    def -=(elem1: K, elem2: K, elems: K*): IndexedState[S1, S2, Set[K]] =
      lens %= (_ - elem1 - elem2 diff elems.toSet)

    def --=(xs: IterableOnce[K]): IndexedState[S1, S2, Set[K]] =
      lens %= (_ diff xs.iterator.toSet)
  }

  /** A lens that views a Set can provide the appearance of in place mutation */
  implicit def setLensFamily[S1, S2, K](lens: LensFamily[S1, S2, Set[K], Set[K]]): SetLensFamily[S1, S2, K] =
    SetLensFamily[S1, S2, K](lens)

  type MapLens[S, K, V] = MapLensFamily[S, S, K, V]
  val MapLens: MapLensFamily.type = MapLensFamily
  /** A lens that views an immutable Map type can provide a mutable.Map-like API via State */
  case class MapLensFamily[S1, S2, K, V](lens: LensFamily[S1, S2, Map[K, V], Map[K, V]]) {
    /** Allows both viewing and setting the value of a member of the map */
    def member(k: K): LensFamily[S1, S2, Option[V], Option[V]] = lensFamilyg[S1, S2, Option[V], Option[V]](
      s => opt => lens.mod((m: Map[K, V]) => (opt match {
        case Some(v) => m + (k -> v)
        case None    => m - k
      }): Map[K, V], s): Id[S2]
      , s => lens.get(s).get(k))

    /** This lens has undefined behavior when accessing an element not present in the map! */
    def at(k: K): LensFamily[S1, S2, V, V] =
      lensFamilyg[S1, S2, V, V](s => v => lens.mod(_ + (k -> v), s): Id[S2], lens.get(_) apply k)

    def +=(elem1: (K, V), elem2: (K, V), elems: (K, V)*): IndexedState[S1, S2, Map[K, V]] =
      lens %= (_ + elem1 + elem2 ++ elems)

    def +=(elem: (K, V)): IndexedState[S1, S2, Map[K, V]] =
      lens %= (_ + elem)

    def ++=(xs: IterableOnce[(K, V)]): IndexedState[S1, S2, Map[K, V]] =
      lens %= (_ ++ xs)

    def update(key: K, value: V): IndexedState[S1, S2, Unit] =
      lens %== (_.updated(key, value))

    def -=(elem: K): IndexedState[S1, S2, Map[K, V]] =
      lens %= (_ - elem)

    def -=(elem1: K, elem2: K, elems: K*): IndexedState[S1, S2, Map[K, V]] =
      lens %= (_ - elem1 - elem2 -- elems)

    def --=(xs: IterableOnce[K]): IndexedState[S1, S2, Map[K, V]] =
      lens %= (_ -- xs)
  }

  implicit def mapLensFamily[S1, S2, K, V](lens: LensFamily[S1, S2, Map[K, V], Map[K, V]]): MapLensFamily[S1, S2, K, V] =
    MapLensFamily[S1, S2, K, V](lens)

  type SeqLikeLens[S, A, Repr <: SeqLike[A, Repr]] = SeqLikeLensFamily[S, S, A, Repr]
  val SeqLikeLens: SeqLikeLensFamily.type = SeqLikeLensFamily
  /** Provide the appearance of a mutable-like API for sorting sequences through a lens */
  case class SeqLikeLensFamily[S1, S2, A, Repr <: SeqLike[A, Repr]](lens: LensFamily[S1, S2, Repr, Repr]) {
    def sortWith(lt: (A, A) => Boolean): IndexedState[S1, S2, Unit] =
      lens %== (_ sortWith lt)

    def sortBy[B: math.Ordering](f: A => B): IndexedState[S1, S2, Unit] =
      lens %== (_ sortBy f)

    def sort[B >: A](implicit ord: math.Ordering[B]): IndexedState[S1, S2, Unit] =
      lens %== (_.sorted[B])
  }

  implicit def seqLensFamily[S1, S2, A](lens: LensFamily[S1, S2, scala.collection.immutable.Seq[A], scala.collection.immutable.Seq[A]]): SeqLikeLensFamily[S1, S2, A, immutable.Seq[A]] =
    seqLikeLensFamily[S1, S2, A, scala.collection.immutable.Seq[A]](lens)

  type QueueLens[S, A] = QueueLensFamily[S, S, A]
  val QueueLens: QueueLensFamily.type = QueueLensFamily
  /** Provide an imperative-seeming API for queues viewed through a lens */
  case class QueueLensFamily[S1, S2, A](lens: LensFamily[S1, S2, Queue[A], Queue[A]]) {
    def enqueue(elem: A): IndexedState[S1, S2, Unit] =
      lens %== (_ enqueue elem)

    def dequeue: IndexedState[S1, S2, A] =
      lens %%= State[Queue[A], A](_.dequeue.swap)

    def length: State[S1, Int] =
      lens >- (_.length)
  }

  implicit def queueLensFamily[S1, S2, A](lens: LensFamily[S1, S2, Queue[A], Queue[A]]): QueueLensFamily[S1, S2, A] =
    QueueLensFamily[S1, S2, A](lens)

  type ArrayLens[S, A] = ArrayLensFamily[S, S, A]
  val ArrayLens: ArrayLensFamily.type = ArrayLensFamily
  /** Provide an imperative-seeming API for arrays viewed through a lens */
  case class ArrayLensFamily[S1, S2, A](lens: LensFamily[S1, S2, Array[A], Array[A]]) {
    def at(n: Int): LensFamily[S1, S2, A, A] =
      lensFamilyg[S1, S2, A, A](
        s => v => lens.mod(array => {
          val copy = array.clone()
          copy.update(n, v)
          copy
        }, s): Id[S2]
        , s => lens.get(s) apply n
      )

    def length: State[S1, Int] =
      lens >- (_.length)
  }

  implicit def arrayLensFamily[S1, S2, A](lens: LensFamily[S1, S2, Array[A], Array[A]]): ArrayLensFamily[S1, S2, A] =
    ArrayLensFamily[S1, S2, A](lens)

  type NumericLens[S, N] = NumericLensFamily[S, S, N]
  val NumericLens: NumericLensFamily.type = NumericLensFamily
  /** Allow the illusion of imperative updates to numbers viewed through a lens */
  case class NumericLensFamily[S1, S2, N](lens: LensFamily[S1, S2, N, N], num: Numeric[N]) {
    def +=(that: N): IndexedState[S1, S2, N] =
      lens %= (num.plus(_, that))

    def -=(that: N): IndexedState[S1, S2, N] =
      lens %= (num.minus(_, that))

    def *=(that: N): IndexedState[S1, S2, N] =
      lens %= (num.times(_, that))
  }

  implicit def numericLensFamily[S1, S2, N: Numeric](lens: LensFamily[S1, S2, N, N]): NumericLensFamily[S1, S2, N] =
    NumericLens[S1, S2, N](lens, implicitly[Numeric[N]])

  type FractionalLens[S, F] = FractionalLensFamily[S, S, F]
  val FractionalLens: FractionalLensFamily.type = FractionalLensFamily
  /** Allow the illusion of imperative updates to numbers viewed through a lens */
  case class FractionalLensFamily[S1, S2, F](lens: LensFamily[S1, S2, F, F], frac: Fractional[F]) {
    def /=(that: F): IndexedState[S1, S2, F] =
      lens %= (frac.div(_, that))
  }

  implicit def fractionalLensFamily[S1, S2, F: Fractional](lens: LensFamily[S1, S2, F, F]): FractionalLensFamily[S1, S2, F] =
    FractionalLensFamily[S1, S2, F](lens, implicitly[Fractional[F]])

  type IntegralLens[S, I] = IntegralLensFamily[S, S, I]
  val IntegralLens: IntegralLensFamily.type = IntegralLensFamily
  /** Allow the illusion of imperative updates to numbers viewed through a lens */
  case class IntegralLensFamily[S1, S2, I](lens: LensFamily[S1, S2, I, I], ig: Integral[I]) {
    def %=(that: I): IndexedState[S1, S2, I] =
      lens %= (ig.quot(_, that))
  }

  implicit def integralLensFamily[S1, S2, I: Integral](lens: LensFamily[S1, S2, I, I]): IntegralLensFamily[S1, S2, I] =
    IntegralLensFamily[S1, S2, I](lens, implicitly[Integral[I]])

  implicit def tuple2LensFamily[S1, S2, A, B](lens: LensFamily[S1, S2, (A, B), (A, B)]):
  (LensFamily[S1, S2, A, A], LensFamily[S1, S2, B, B]) =
    LensFamilyUnzip[S1, S2].unzip(lens)

  implicit def tuple3LensFamily[S1, S2, A, B, C](lens: LensFamily[S1, S2, (A, B, C), (A, B, C)]):
  (LensFamily[S1, S2, A, A], LensFamily[S1, S2, B, B], LensFamily[S1, S2, C, C]) =
    LensFamilyUnzip[S1, S2].unzip3(lens.xmapbB(tuple3B))

  implicit def tuple4LensFamily[S1, S2, A, B, C, D](lens: LensFamily[S1, S2, (A, B, C, D), (A, B, C, D)]):
  (LensFamily[S1, S2, A, A], LensFamily[S1, S2, B, B], LensFamily[S1, S2, C, C], LensFamily[S1, S2, D, D]) =
    LensFamilyUnzip[S1, S2].unzip4(lens.xmapbB(tuple4B))

  implicit def tuple5LensFamily[S1, S2, A, B, C, D, E](lens: LensFamily[S1, S2, (A, B, C, D, E), (A, B, C, D, E)]):
  (LensFamily[S1, S2, A, A], LensFamily[S1, S2, B, B], LensFamily[S1, S2, C, C], LensFamily[S1, S2, D, D], LensFamily[S1, S2, E, E]) =
    LensFamilyUnzip[S1, S2].unzip5(lens.xmapbB(tuple5B))

  implicit def tuple6LensFamily[S1, S2, A, B, C, D, E, H](lens: LensFamily[S1, S2, (A, B, C, D, E, H), (A, B, C, D, E, H)]):
  (LensFamily[S1, S2, A, A], LensFamily[S1, S2, B, B], LensFamily[S1, S2, C, C], LensFamily[S1, S2, D, D], LensFamily[S1, S2, E, E], LensFamily[S1, S2, H, H]) =
    LensFamilyUnzip[S1, S2].unzip6(lens.xmapbB(tuple6B))

  implicit def tuple7LensFamily[S1, S2, A, B, C, D, E, H, I](lens: LensFamily[S1, S2, (A, B, C, D, E, H, I), (A, B, C, D, E, H, I)]):
  (LensFamily[S1, S2, A, A], LensFamily[S1, S2, B, B], LensFamily[S1, S2, C, C], LensFamily[S1, S2, D, D], LensFamily[S1, S2, E, E], LensFamily[S1, S2, H, H], LensFamily[S1, S2, I, I]) =
    LensFamilyUnzip[S1, S2].unzip7(lens.xmapbB(tuple7B))
}

private[scalaz] trait LensCategory
  extends Choice[Lens]
  with Split[Lens] {

  def compose[A, B, C](bc: Lens[B, C], ab: Lens[A, B]): Lens[A, C] = ab >=> bc

  def id[A] = LensFamily.lensId

  def choice[A, B, C](f: => Lens[A, C], g: => Lens[B, C]): Lens[A \/ B, C] =
    LensFamily.lens {
      case -\/(a) =>
        f run a map (\/.left)
      case \/-(b) =>
        g run b map (\/.right)
    }

  def split[A, B, C, D](f: Lens[A, B], g: Lens[C, D]): Lens[(A,  C), (B, D)] =
    f *** g

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy