Stall
Stall[A, B, S, T]
is a data type shaped like a Profunctor, which characterizes the construction of an AffineTraversal and AnAffineTraversal.
AffineTraversal_[S, T, A, B]
and AnAffineTraversal_[S, T, A, B]
both take two functions as arguments, viewOrModify: S => Either[T, A]
, which is a matching function that produces an Either[T, A]
given an S
,
and set: S => B => T
function which takes a structure S
and a new focus B
and returns a structure of T
.
Stall[A, B, S, T]
also takes these two function, thus making it a data type that embeds the way to construct an AffineTraversal or AnAffineTraversal.
case class Stall[A, B, S, T](viewOrModify: S => Either[T, A], set: S => B => T)
While AffineTraversal and AnAffineTraversal construction is the same, their internal encodings is different.
AffineTraversal
object AffineTraversal_ {
def apply[S, T, A, B](viewOrModify: S => Either[T, A])(set: S => B => T): AffineTraversal_[S, T, A, B]
}
AffineTraversal_[S, T, A, B]
is a function P[A, B] => P[S, T]
that takes a Choice, and
Strong of P[_, _].
abstract class AffineTraversal_[S, T, A, B] {
def apply[P[_, _]](pab: P[A, B])(implicit ev0: Choice[P], ev1: Strong[P]): P[S, T]
}
AnAffineTraversal
object AnAffineTraversal_ {
def apply[S, T, A, B](viewOrModify: S => Either[T, A])(set: S => B => T): AnAffineTraversal_[S, T, A, B]
}
AnAffineTraversal_[S, T, A, B]
is a function P[A, B] => P[S, T]
where's the P[_, _]
is a data type of Stall
abstract class AnAffineTraversal_[S, T, A, B] {
def apply(pab: Stall[A, B, A, B]): Stall[A, B, S, T]
}
In order for AnAffineTraversal_[S, T, A, B]
to be compatible with AffineTraversal_[S, T, A, B]
, an instance of Strong of Stall
and an instance of Choice of Stall
were
introduced.
Strong and Choice both are type constructors that takes 2 type parameters. Stall[A, B, S, T]
is a type that has 4 type parameters, so we need
to fix two of the type parameters of Stall
in order to create an instance of Strong of Stall
and Choice of Stall
.
implicit def strongStall[E, F]: Strong[({ type P[S, T] = Stall[E, F, S, T] })#P] =
new Strong[({ type P[S, T] = Stall[E, F, S, T] })#P] {
override def first[A, B, C](fa: Stall[E, F, A, B]): Stall[E, F, (A, C), (B, C)] =
Stall(
{ case (a, c) => fa.viewOrModify(a).leftMap((_, c)) },
{ case (a, c) =>
f => (fa.set(a)(f), c)
})
override def second[A, B, C](fa: Stall[E, F, A, B]): Stall[E, F, (C, A), (C, B)] =
Stall(
{ case (c, a) => fa.viewOrModify(a).leftMap((c, _)) },
{ case (c, a) =>
f => (c, fa.set(a)(f))
})
override def dimap[A, B, C, D](fab: Stall[E, F, A, B])
(f: C => A)
(g: B => D): Stall[E, F, C, D] =
Stall(c => fab.viewOrModify(f(c)).leftMap(g), c => ff => g(fab.set(f(c))(ff)))
}
implicit def choiceStall[E, F]: Choice[({ type P[S, T] = Stall[E, F, S, T] })#P] =
new Choice[({ type P[S, T] = Stall[E, F, S, T] })#P] {
override def left[A, B, C](pab: Stall[E, F, A, B]): Stall[E, F, Either[A, C], Either[B, C]] =
Stall(
{
case Left(a) => pab.viewOrModify(a).fold(_.asLeft[C].asLeft[E], _.asRight[Either[B, C]])
case Right(c) => c.asRight[B].asLeft[E]
},
either => f => either.leftMap(pab.set(_)(f))
)
override def right[A, B, C](pab: Stall[E, F, A, B]): Stall[E, F, Either[C, A], Either[C, B]] =
Stall(
{
case Left(c) => c.asLeft[B].asLeft[E]
case Right(a) => pab.viewOrModify(a).fold(_.asRight[C].asLeft[E], _.asRight[Either[C, B]])
},
either => f => either.map(pab.set(_)(f))
)
override def dimap[A, B, C, D](fab: Stall[E, F, A, B])
(f: C => A)
(g: B => D): Stall[E, F, C, D] =
Stall(c => fab.viewOrModify(f(c)).leftMap(g), c => ff => g(fab.set(f(c))(ff)))
}
AnAffineTraversal allows us to export its internal construction logic to a Stall
using the toStall
method.
import proptics.AnAffineTraversal
// import proptics.AnAffineTraversal
sealed trait Json
// defined trait Json
case object JNull extends Json
// defined object JNull
case class JNumber(value: Double) extends Json
// defined class JNumber
val jsonAffineTraversal =
AnAffineTraversal.fromPartial[Json, Double] { case JNumber(i) => i } { json => i =>
json match {
case JNumber(_) => JNumber(i)
case _ => json
}
}
// jsonAffineTraversal: AnAffineTraversal[Json,Double] = AnAffineTraversal_$$anon$6@27ce826e
val stall = jsonAffineTraversal.toStall
// stall: proptics.internal.Stall[Double,Double,Json,Json] =
// Stall(proptics.AnAffineTraversal_$$$Lambda$6037/0x0000000801cb3040@1adf1c6a,
// proptics.AnAffineTraversal_$$$Lambda$6038/0x0000000801cb3840@1a9cda87)
stall.viewOrModify(JNumber(9))
// res0: Either[Json,Double] = Right(9.0)
stall.set(JNumber(1))(9)
// res1: Json = JNumber(9.0)
We can later on create a new instance of an AnAffineTraversal or an AffineTraversal from the stall instance
import proptics.AffineTraversal
// import proptics.AffineTraversal
import proptics.AnAffineTraversal
// import proptics.AnAffineTraversal
val anAffineTraversalFromStall: AnAffineTraversal[Json, Double] =
AnAffineTraversal[Json, Double](stall.viewOrModify)(stall.set)
// anAffineTraversalFromStall: proptics.AnAffineTraversal[Json,Double] =
// proptics.AnAffineTraversal_$$anon$6@77d28f9
val affineTraversalFromStall: AffineTraversal[Json, Double] =
AffineTraversal[Json, Double](stall.viewOrModify)(stall.set)
// affineTraversalFromStall: proptics.AffineTraversal[Json,Double] =
// proptics.AffineTraversal_$$anon$10@7995e246