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(NonEmptyList.nel(l.head, _), l.tail))
/** 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 => {
lazy val x = q.pos
lazy val y = q put x
Store(b =>
Store(w => if(e equal (x, w)) b else y, x), y)
})
def predicateLens[A]: Store[A, Boolean] @> (A \/ A) =
lens(q => Store(_ match {
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