alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (PLens.scala)

This example Scala source code file (PLens.scala) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Scala by Example" TM.

Learn more about this Scala project at its project page.

Java - Scala tags/keywords

none, plensfamily

The PLens.scala Scala example source code

package scalaz

/**
 * Partial Lens Families, offering a purely functional means to access and retrieve
 * an optional field transitioning from type `B1` to type `B2` in a record that is
 * simultaneously transitioning from type `A1` to type `A2`.  [[scalaz.PLens]] 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 partial lens
 * family can address the nth element of a `List`.
 *
 * @see [[scalaz.Lens]]
 *
 * @tparam A1 The initial type of the record
 * @tparam A2 The final type of the record
 * @tparam B1 The initial type of the optional field
 * @tparam B2 The final type of the optional field
 */
sealed abstract class PLensFamily[A1, A2, B1, B2] {
  def run(a: A1): Option[IndexedStore[B1, B2, A2]]

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

  import BijectionT._
  import PLensFamily._

  def kleisli: Kleisli[Option, A1, IndexedStore[B1, B2, A2]] =
    Kleisli[Option, A1, IndexedStore[B1, B2, A2]](apply(_))

  def xmapA[X1, X2](f: A2 => X2)(g: X1 => A1): PLensFamily[X1, X2, B1, B2] =
    plensFamily(x => apply(g(x)) map (_ map (f)))

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

  def xmapB[X1, X2](f: B1 => X1)(g: X2 => B2): PLensFamily[A1, A2, X1, X2] =
    plensFamily(a => apply(a) map (_.xmap(f)(g)))

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

  def get(a: A1): Option[B1] =
    run(a) map (_.pos)

  def getK: Kleisli[Option, A1, B1] =
    Kleisli[Option, A1, B1](get(_))

  /** If the Partial Lens is null, then return the given default value. */
  def getOr(a: A1, b: => B1): B1 =
    get(a) getOrElse b

  def getOrZ(a: A1)(implicit M: Monoid[B1]): B1 =
    getOr(a, M.zero)

  def set(a: A1, b: B2): Option[A2] =
    run(a) map (_.put(b))

  def setK(a: A1): Kleisli[Option, B2, A2] =
    Kleisli[Option, B2, A2](set(a, _))

  def setOr(a: A1, b: B2, d: => A2): A2 =
    set(a, b) getOrElse d

  def setOrZ(a: A1, b: B2)(implicit M: Monoid[A2]): A2 =
    setOr(a, b, M.zero)

  def trySet(a: A1): Option[B2 => A2] =
    run(a) map (c => c put _)

  def trySetK: Kleisli[Option, A1, B2 => A2] =
    Kleisli[Option, A1, B2 => A2](trySet(_))

  def trySetOr(a: A1, d: => B2 => A2): B2 => A2 =
    trySet(a) getOrElse d

  def trySetOrZ(a: A1)(implicit M: Monoid[A2]): B2 => A2 =
    trySetOr(a, _ => M.zero)

  /** If the Partial Lens is null, then return the target object, otherwise run the function on its projection. */
  def as(f: B1 => A1, a: A1): A1 =
    get(a) match {
      case None => a
      case Some(w) => f(w)
    }

  def is(a: A1): Boolean =
    run(a).isDefined

  def isNot(a: A1): Boolean =
    !is(a)

  def exists(p: B1 => Boolean, a: A1): Boolean =
    get(a) exists p

  def forall(p: B1 => Boolean, a: A1): Boolean =
    get(a) forall p

  def modg(f: B1 => B2, a: A1): Option[A2] =
    run(a).map(_ puts f)

  def =?>=(f: B1 => B2): A1 => Option[A2] =
    modg(f, _)

  /** Modify the potential value viewed through the partial lens */
  def mod[A >: A2 <: A1](f: B1 => B2, a: A): A =
    run(a) match {
      case None => a: A
      case Some(w) => (w puts f): A
    }

  def =>=[A >: A2 <: A1](f: B1 => B2): A => A =
    mod(f, _)

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

  def %=[A >: A2 <: A1](f: B1 => B2): PState[A, B2] =
    State(a => run(a) match {
      case None => (a, None)
      case Some(w) => {
        val r = f(w.pos)
        (w put r, Some(r))
      }
    })

  def :=[A >: A2 <: A1](b: => B2): PState[A, B2] =
    %=(_ => b)

  def %==[A >: A2 <: A1](f: B1 => B2): State[A, Unit] =
    State(a =>
  (mod(f, a), ()))

  def %%=[A >: A2 <: A1, C](s: IndexedState[B1, B2, C]): PState[A, C] =
    State(a => run(a) match {
      case None => (a, None)
      case Some(w) => {
        val r = s.run(w.pos): (B2, C)
        (w put r._1, Some(r._2))
      }
    })

  def >-[A >: A2 <: A1, C](f: B1 => C): PState[A, C] =
    State(a => (a, get(a) map f))

  def >>-[A >: A2 <: A1, C](f: B1 => State[A, C]): PState[A, C] =
    StateT(a => get(a) match {
      case None => (a, None)
      case Some(w) =>
        f(w) apply a match {
          case (y, x) => (y, Some(x))
        }
    })

  def ->>-[A >: A2 <: A1, C](f: => State[A, C]): PState[A, C] =
    >>-(_ => f)

  /** Partial Lenses can be composed */
  def compose[C1, C2](that: PLensFamily[C1, C2, A1, A2]): PLensFamily[C1, C2, B1, B2] =
    plensFamily(c =>
      (that run c).flatMap (x => {
        val (ac, a) = x.run
        run(a) map (y => {
          val (ba, b) = y.run
          IndexedStore(ac compose ba, b)
        })
      }))

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

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

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

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

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

  /** Two disjoint partial lenses can be paired */
  def product[C1, C2, D1, D2](that: PLensFamily[C1, C2, D1, D2]): PLensFamily[(A1, C1), (A2, C2), (B1, D1), (B2, D2)] =
    plensFamily {
      case (a, c) =>
        for {
          q <- run(a)
          r <- that run c
        } yield q *** r
    }

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

}

object PLensFamily extends PLensInstances with PLensFunctions {

  def apply[A1, A2, B1, B2](r: A1 => Option[IndexedStore[B1, B2, A2]]): PLensFamily[A1, A2, B1, B2] =
    plensFamily(r)
}

trait PLensFamilyFunctions extends PLensInstances {

  import BijectionT._

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

  def plensFamilyf[A1, A2, B1, B2](r: PartialFunction[A1, IndexedStore[B1, B2, A2]]): PLensFamily[A1, A2, B1, B2] =
    plensFamily(r.lift)

  def plensFamilyg[A1, A2, B1, B2](set: A1 => Option[B2 => A2], get: A1 => Option[B1]): PLensFamily[A1, A2, B1, B2] =
    plensFamily(a => for {
      w <- set(a)
      x <- get(a)
    } yield IndexedStore(w, x))

  /** The identity partial lens family for a given pair of objects */
  def plensFamilyId[A1, A2]: PLensFamily[A1, A2, A1, A2] =
    LensFamily.lensFamilyId[A1, A2].partial

  /** A partial lens family that discards the choice of right or left from disjunction */
  def codiagPLensFamily[A1, A2]: PLensFamily[A1 \/ A1, A2 \/ A2, A1, A2] =
    plensFamilyId[A1, A2] ||| plensFamilyId[A1, A2]

  /** The always-null partial lens family */
  def nilFamily[A1, A2, B1, B2]: PLensFamily[A1, A2, B1, B2] =
    plensFamily(_ => None)

  def somePLensFamily[A1, A2]: PLensFamily[Option[A1], Option[A2], A1, A2] =
    plensFamily(_ map (z => IndexedStore(Some(_), z)))

  def leftPLensFamily[A1, A2, B]: PLensFamily[A1 \/ B, A2 \/ B, A1, A2] =
    plensFamily {
      case -\/(a) => Some(IndexedStore(\/.left, a))
      case \/-(_) => None
    }

  def rightPLensFamily[A, B1, B2]: PLensFamily[A \/ B1, A \/ B2, B1, B2] =
    plensFamily {
      case \/-(b) => Some(IndexedStore(\/.right, b))
      case -\/(_) => None
    }

  def tuple2PLensFamily[S1, S2, A, B](lens: PLensFamily[S1, S2, (A, B), (A, B)]):
  (PLensFamily[S1, S2, A, A], PLensFamily[S1, S2, B, B]) =
    PLensFamilyUnzip[S1, S2].unzip(lens)

  def tuple3PLensFamily[S1, S2, A, B, C](lens: PLensFamily[S1, S2, (A, B, C), (A, B, C)]):
  (PLensFamily[S1, S2, A, A], PLensFamily[S1, S2, B, B], PLensFamily[S1, S2, C, C]) =
    PLensFamilyUnzip[S1, S2].unzip3(lens.xmapbB(tuple3B))

  def tuple4PLensFamily[S1, S2, A, B, C, D](lens: PLensFamily[S1, S2, (A, B, C, D), (A, B, C, D)]):
  (PLensFamily[S1, S2, A, A], PLensFamily[S1, S2, B, B], PLensFamily[S1, S2, C, C], PLensFamily[S1, S2, D, D]) =
    PLensFamilyUnzip[S1, S2].unzip4(lens.xmapbB(tuple4B))

  def tuple5PLensFamily[S1, S2, A, B, C, D, E](lens: PLensFamily[S1, S2, (A, B, C, D, E), (A, B, C, D, E)]):
  (PLensFamily[S1, S2, A, A], PLensFamily[S1, S2, B, B], PLensFamily[S1, S2, C, C], PLensFamily[S1, S2, D, D], PLensFamily[S1, S2, E, E]) =
    PLensFamilyUnzip[S1, S2].unzip5(lens.xmapbB(tuple5B))

  def tuple6PLensFamily[S1, S2, A, B, C, D, E, H](lens: PLensFamily[S1, S2, (A, B, C, D, E, H), (A, B, C, D, E, H)]):
  (PLensFamily[S1, S2, A, A], PLensFamily[S1, S2, B, B], PLensFamily[S1, S2, C, C], PLensFamily[S1, S2, D, D], PLensFamily[S1, S2, E, E], PLensFamily[S1, S2, H, H]) =
    PLensFamilyUnzip[S1, S2].unzip6(lens.xmapbB(tuple6B))

  def tuple7PLensFamily[S1, S2, A, B, C, D, E, H, I](lens: PLensFamily[S1, S2, (A, B, C, D, E, H, I), (A, B, C, D, E, H, I)]):
  (PLensFamily[S1, S2, A, A], PLensFamily[S1, S2, B, B], PLensFamily[S1, S2, C, C], PLensFamily[S1, S2, D, D], PLensFamily[S1, S2, E, E], PLensFamily[S1, S2, H, H], PLensFamily[S1, S2, I, I]) =
    PLensFamilyUnzip[S1, S2].unzip7(lens.xmapbB(tuple7B))

  def eitherLensFamily[S1, S2, A, B](l: PLensFamily[S1, S2, A \/ B, A \/ B]): (PLensFamily[S1, S2, A, A], PLensFamily[S1, S2, B, B]) =
    (
    leftPLensFamily compose l
    , rightPLensFamily compose l
    )

  import LazyOption._

  def lazySomePLensFamily[A1, A2]: PLensFamily[LazyOption[A1], LazyOption[A2], A1, A2] =
    plensFamily(_.fold(z => Some(IndexedStore(lazySome(_), z)), None))

  import LazyEither._

  def lazyLeftPLensFamily[A1, A2, B]: PLensFamily[LazyEither[A1, B], LazyEither[A2, B], A1, A2] =
    plensFamily(_.fold(a => Some(IndexedStore(lazyLeft(_), a)), _ => None))

  def lazyRightPLensFamily[A, B1, B2]: PLensFamily[LazyEither[A, B1], LazyEither[A, B2], B1, B2] =
    plensFamily(_.fold(_ => None, b => Some(IndexedStore(lazyRight(_), b))))

  def factorPLensFamily[A1, A2, B1, B2, C1, C2]: PLensFamily[((A1, B1) \/ (A1, C1)), ((A2, B2) \/ (A2, C2)), (A1, B1 \/ C1), (A2, B2 \/ C2)] =
    ~LensFamily.factorLensFamily

  def distributePLensFamily[A1, A2, B1, B2, C1, C2]: PLensFamily[(A1, B1 \/ C1), (A2, B2 \/ C2), ((A1, B1) \/ (A1, C1)), ((A2, B2) \/ (A2, C2))] =
    ~LensFamily.distributeLensFamily
}

trait PLensFunctions extends PLensInstances with PLensFamilyFunctions {
  import BijectionT._

  def plens[A, B](r: A => Option[Store[B, A]]): PLens[A, B] = new PLens[A, B] {
    def run(a: A): Option[Store[B, A]] = r(a)
  }

  def plensf[A, B](r: PartialFunction[A, Store[B, A]]): PLens[A, B] =
    plens(r.lift)

  def plensg[A, B](set: A => Option[B => A], get: A => Option[B]): PLens[A, B] =
    plens(a => for {
      w <- set(a)
      x <- get(a)
    } yield Store(w, x))

  def plensgf[A, B](set: PartialFunction[A, B => A], get: PartialFunction[A, B]): PLens[A, B] =
    plensg(set.lift, get.lift)

  /** The identity partial lens for a given object */
  def plensId[A]: PLens[A, A] =
    LensFamily.lensId[A].partial

  /** The trivial partial lens that can retrieve Unit from anything */
  def trivialPLens[A]: PLens[A, Unit] =
    LensFamily.trivialLens[A].partial

  /** A lens that discards the choice of right or left from disjunction */
  def codiagPLens[A]: PLens[A \/ A, A] =
    plensId[A] ||| plensId[A]

  /** The always-null partial lens */
  def nil[A, B]: PLens[A, B] =
    plens(_ => None)

  def somePLens[A]: Option[A] @?> A =
    plens(_ map (z => Store(Some(_), z)))

  def leftPLens[A, B]: (A \/ B) @?> A =
    plens {
      case -\/(a) => Some(Store(\/.left, a))
      case \/-(_) => None
    }

  def rightPLens[A, B]: (A \/ B) @?> B =
    plens {
      case \/-(b) => Some(Store(\/.right, b))
      case -\/(_) => None
    }

  def tuple2PLens[S, A, B](lens: PLens[S, (A, B)]):
  (PLens[S, A], PLens[S, B]) =
    PLensFamilyUnzip[S, S].unzip(lens)

  def tuple3PLens[S, A, B, C](lens: PLens[S, (A, B, C)]):
  (PLens[S, A], PLens[S, B], PLens[S, C]) =
    PLensFamilyUnzip[S, S].unzip3(lens.xmapbB(tuple3B))

  def tuple4PLens[ S, A, B, C, D](lens: PLens[S, (A, B, C, D)]):
  (PLens[S, A], PLens[S, B], PLens[S, C], PLens[S, D]) =
    PLensFamilyUnzip[S, S].unzip4(lens.xmapbB(tuple4B))

  def tuple5PLens[S, A, B, C, D, E](lens: PLens[S, (A, B, C, D, E)]):
  (PLens[S, A], PLens[S, B], PLens[S, C], PLens[S, D], PLens[S, E]) =
    PLensFamilyUnzip[S, S].unzip5(lens.xmapbB(tuple5B))

  def tuple6PLens[S, A, B, C, D, E, H](lens: PLens[S, (A, B, C, D, E, H)]):
  (PLens[S, A], PLens[S, B], PLens[S, C], PLens[S, D], PLens[S, E], PLens[S, H]) =
    PLensFamilyUnzip[S, S].unzip6(lens.xmapbB(tuple6B))

  def tuple7PLens[S, A, B, C, D, E, H, I](lens: PLens[S, (A, B, C, D, E, H, I)]):
  (PLens[S, A], PLens[S, B], PLens[S, C], PLens[S, D], PLens[S, E], PLens[S, H], PLens[S, I]) =
    PLensFamilyUnzip[S, S].unzip7(lens.xmapbB(tuple7B))

  def eitherLens[S, A, B](l: S @?> (A \/ B)): (S @?> A, S @?> B) =
    (
    leftPLens compose l
    , rightPLens compose l
    )

  import LazyOption._

  def lazySomePLens[A]: LazyOption[A] @?> A =
    plens(_.fold(z => Some(Store(lazySome(_), z)), None))

  import LazyEither._

  def lazyLeftPLens[A, B]: LazyEither[A, B] @?> A =
    plens(_.fold(a => Some(Store(lazyLeft(_), a)), _ => None))

  def lazyRightPLens[A, B]: LazyEither[A, B] @?> B =
    plens(_.fold(_ => None, b => Some(Store(lazyRight(_), b))))

  def listHeadPLens[A]: List[A] @?> A =
    plens {
      case Nil => None
      case h :: t => Some(Store(_ :: t, h))
    }

  def listTailPLens[A]: List[A] @?> List[A] =
    plens {
      case Nil => None
      case h :: t => Some(Store(h :: _, t))
    }

  def listNthPLens[A](n: Int): List[A] @?> A =
    if(n < 0)
      nil
    else if(n == 0)
      listHeadPLens
    else
      listNthPLens(n - 1) compose listTailPLens

  def listLookupByPLens[K, V](p: K => Boolean): List[(K, V)] @?> V = {
    @annotation.tailrec
    def lookupr(t: (List[(K, V)], (K, V), List[(K, V)])): Option[(List[(K, V)], (K, V), List[(K, V)])] =
      t match {
        case (_, (k, _), _) if p(k) => Some(t)
        case (_, _     , Nil)       => None
        case (l, x     , r::rs)     => lookupr(x::l, r, rs)
      }
    plens {
      case Nil => None
      case h :: t => lookupr(Nil, h, t) map {
        case (l, (k, v), r) => Store(w => l reverse_::: (k, w) :: r, v)
      }
    }
  }

  def listLookupPLens[K: Equal, V](k: K): List[(K, V)] @?> V =
    listLookupByPLens(Equal[K].equal(k, _))

  def vectorHeadPLens[A]: Vector[A] @?> A =
    vectorNthPLens(0)

  def vectorNthPLens[A](n: Int): Vector[A] @?> A =
    plens(v =>
      v.lift(n) map (a => Store(x => v patch (n, Vector(x), 1), a)))

  def vectorLastPLens[A]: Vector[A] @?> A =
    plens(v =>
      v.lastOption map (a => Store(x => v patch (v.length - 1, Vector(x), 1), a)))

  import Stream._

  def streamHeadPLens[A]: Stream[A] @?> A =
    plens {
      case Empty => None
      case h #:: t => Some(Store(_ #:: t, h))
    }

  def streamTailPLens[A]: Stream[A] @?> Stream[A] =
    plens {
      case Empty => None
      case h #:: t => Some(Store(h #:: _, t))
    }

  def streamNthPLens[A](n: Int): Stream[A] @?> A =
    if(n < 0)
      nil
    else if(n == 0)
      streamHeadPLens
    else
      streamNthPLens(n - 1) compose streamTailPLens

  def streamLookupByPLens[K, V](p: K => Boolean): Stream[(K, V)] @?> V = {
    @annotation.tailrec
    def lookupr(t: (Stream[(K, V)], (K, V), Stream[(K, V)])): Option[(Stream[(K, V)], (K, V), Stream[(K, V)])] =
      t match {
        case (_, (k, _), _) if p(k)    => Some(t)
        case (_, _     , Stream.Empty) => None
        case (l, x     , r #:: rs)     => lookupr(x #:: l, r, rs)
      }
    plens {
      case Stream.Empty => None
      case h #:: t => lookupr(Stream.empty, h, t) map {
        case (l, (k, v), r) => Store(w => l.reverse #::: (k, w) #:: r, v)
      }
    }
  }

  def streamLookupPLens[K: Equal, V](k: K): Stream[(K, V)] @?> V =
    streamLookupByPLens(Equal[K].equal(k, _))

  def ephemeralStreamHeadPLens[A]: EphemeralStream[A] @?> A =
    plens(s =>
      if(s.isEmpty)
        None
      else
        Some(Store(EphemeralStream.cons(_, s.tail()), s.head()))
    )

  def ephemeralStreamTailPLens[A]: EphemeralStream[A] @?> EphemeralStream[A] =
    plens(s =>
      if(s.isEmpty)
        None
      else
        Some(Store(EphemeralStream.cons(s.head(), _), s.tail()))
    )

  def ephemeralStreamNthPLens[A](n: Int): EphemeralStream[A] @?> A =
    if(n < 0)
      nil
    else if(n == 0)
      ephemeralStreamHeadPLens
    else
      ephemeralStreamNthPLens(n - 1) compose ephemeralStreamTailPLens

  def ephemeralStreamLookupByPLens[K, V](p: K => Boolean): EphemeralStream[(K, V)] @?> V = {
    import EphemeralStream.cons

    @annotation.tailrec
    def lookupr(t: (EphemeralStream[(K, V)], (K, V), EphemeralStream[(K, V)])): Option[(EphemeralStream[(K, V)], (K, V), EphemeralStream[(K, V)])] =
      t match {
        case (_, (k, _), _) if p(k)    => Some(t)
        case (l, x     , s) =>
            if(s.isEmpty)
              None
            else
              lookupr((cons(x, l), s.head(), s.tail()))
      }
    plens(s =>
      if(s.isEmpty)
        None
      else
        lookupr((EphemeralStream.emptyEphemeralStream, s.head(), s.tail())) map {
          case (l, (k, v), r) => Store(w => l.reverse ++ cons((k, w), r), v)
        }
    )
  }

  def ephemeralStreamLookupPLens[K: Equal, V](k: K): EphemeralStream[(K, V)] @?> V =
    ephemeralStreamLookupByPLens(Equal[K].equal(k, _))

  import LensFamily.mapVLens

  def mapVPLens[K, V](k: K): Map[K, V] @?> V =
    somePLens compose ~mapVLens[K, V](k)

  def factorPLens[A, B, C]: ((A, B) \/ (A, C)) @?> (A, B \/ C) =
    ~LensFamily.factorLens

  def distributePLens[A, B, C]: (A, B \/ C) @?> ((A, B) \/ (A, C)) =
    ~LensFamily.distributeLens
}

abstract class PLensInstances {

  import PLensFamily._

  implicit val plensCategory: PLensCategory = new PLensCategory {
  }

  /** Partial Lenses may be used implicitly as State monadic actions that get the potentially viewed portion of the state */
  implicit def PLensFamilyState[A, B](plens: PLensFamily[A, _, B, _]): PState[A, B] =
    plens.st

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

  /** Allow the illusion of imperative updates to potential numbers viewed through a partial lens */
  case class NumericPLens[S, N: Numeric](lens: S @?> N, num: Numeric[N]) {
    def +=(that: N): PState[S, N] =
      lens %= (num.plus(_, that))

    def -=(that: N): PState[S, N] =
      lens %= (num.minus(_, that))

    def *=(that: N): PState[S, N] =
      lens %= (num.times(_, that))
  }

  implicit def numericPLens[S, N: Numeric](lens: S @?> N) =
    NumericPLens[S, N](lens, implicitly[Numeric[N]])

  /** Allow the illusion of imperative updates to potential numbers viewed through a partial lens */
  case class FractionalPLens[S, F](lens: S @?> F, frac: Fractional[F]) {
    def /=(that: F): PState[S, F] =
      lens %= (frac.div(_, that))
  }

  implicit def fractionalPLens[S, F: Fractional](lens: S @?> F) =
    FractionalPLens[S, F](lens, implicitly[Fractional[F]])

  /** Allow the illusion of imperative updates to potential numbers viewed through a partial lens */
  case class IntegralPLens[S, I](lens: S @?> I, ig: Integral[I]) {
    def %=(that: I): PState[S, I] =
      lens %= (ig.quot(_, that))
  }

  implicit def integralPLens[S, I: Integral](lens: S @?> I) =
    IntegralPLens[S, I](lens, implicitly[Integral[I]])

}

private[scalaz] trait PLensCategory
  extends Choice[PLens]
  with Split[PLens] {

  def compose[A, B, C](bc: PLens[B, C], ab: PLens[A, B]): PLens[A, C] = ab >=> bc
  def id[A]: PLens[A, A] = PLensFamily.plensId

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

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

Other Scala examples (source code examples)

Here is a short list of links related to this Scala PLens.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.