AnIso
AnIso
is similar to Iso, but has different internal encodings, it enables
you to transform back and forth between two types without losing information.
AnIso
is useful when you need to convert between types, a simple example would be, transform a String
into a List[Char]
.
AnIso internal encoding
Polymorphic AnIso
AnIso_[S, T, A, B]
AnIso_[S, T, A, B]
is a function P[A, B] => P[S, T]
where's the P[_, _]
is a data type of Exchange, thus making
it a function Exchange[A, B, A, B] => Exchange[A, B, S, T]
.
/**
* @tparam S the source of a AnIso_
* @tparam T the modified source of an AnIso_
* @tparam A the focus of an AnIso_
* @tparam B the modified focus of an AnIso_
*/
abstract class AnIso_[S, T, A, B] {
def apply(exchange: Exchange[A, B, A, B]): Exchange[A, B, S, T]
}
AnIso_[S, T, A, B]
changes its focus from A
to B
, resulting in a change of type to the full structure from
S
to T
.
AnIso
that changes its focus/structure, is called Polymorphic AnIso
.
Monomorphic Iso
AnIso[S, A]
AnIso[S, A]
is a type alias for AnIso_[S, S, A, A]
, which has the same type of focus A
, thus preserving the same type of structure S
.
type AnIso[S, A] = AnIso_[S, S, A, A]
AnIso[S, A]
means that S
and A
are isomorphic – the two types represent the same information.
AnIso
that does not change its focus/structure, is called Monomorphic AnIso
.
Constructing AnIsos
AnIso_[S, T, A, B]
is constructed using the AnIso_[S, T, A, B]#apply function.
For a given AnIso_[S, T, A, B]
it takes two conversion functions as arguments, view: S => A
which produces an A
given an S
,
and review: B => T
which produces a T
given an B
.
object AnIso_ {
def apply[S, T, A, B](view: S => A)(review: B => T): AnIso_[S, T, A, B]
}
AnIso[S, A]
is constructed using the AnIso[S, A]#apply function. For a given AnIso[S, A]
it takes two conversion functions as arguments,
view: S => A
which produces an A
given an S
, and review: A => S
which produces an S
given an A
.
object AnIso {
def apply[S, A](view: S => A)(review: A => S): AnIso[S, A]
}
import proptics.AnIso
// import proptics.AnIso
val anIsoStringToList = AnIso[String, List[Char]](_.toList)(_.mkString)
// anIsoStringToList: proptics.Iso[String,List[Char]] = proptics.Iso_$$anon$16@4b898027
Common functions of an AnIso
view
anIsoStringToList.view("Proptics")
// res0: List[Char] = List(P, r, o, p, t, i, c, s)
review
anIsoStringToList.review(chars)
// res1: String = Proptics
exists
anIsoStringToList.exists(_.length === 8)("Proptics")
// res2: Boolean = true
contains
anIsoStringToList.contains(_.contains(80))("Proptics")
// res3: Boolean = true
find
anIsoStringToList.find(_.contains(80))("Proptics")
// res4: Option[List[Char]] = Some(List(P, r, o, p, t, i, c, s))
Exporting Exchange as data type of AnIso
AnIso
allows us to export its internal construction logic to an Exchange
using the toExchange
method.
import proptics.AnIso
// import proptics.AnIso
val anIsoStringToList: AnIso[String, List[Char]] = AnIso[String, List[Char]](_.toList)(_.mkString)
// anIsoStringToList: proptics.AnIso[String,List[Char]] = proptics.AnIso_$$anon$17@74561208
val exchange = anIsoStringToList.toExchange
// exchange: proptics.internal.Exchange[List[Char],List[Char],String,String] =
// Exchange(scala.Function1$$Lambda$9364/0x0000000801a34040@419490d4,
// scala.Function1$$Lambda$9364/0x0000000801a34040@78d86219)
anIsoStringToList.view("Proptics")
// res0: List[Char] = List(P, r, o, p, t, i, c, s)
exchange.review("Proptics".toList)
// res1: String = Proptics
We can later on create a new instance of AnIso
or Iso
from the exchange instance
import proptics.Iso
// import proptics.Iso
val anIsoFromExchange: AnIso[String, List[Char]] =
AnIso[String, List[Char]](exchange.view)(exchange.review)
// anIsoFromExchange: proptics.AnIso[String,List[Char]] = proptics.AnIso_$$anon$17@bf55e9c
val isoFromExchange: Iso[String, List[Char]] = Iso[String, List[Char]](exchange.view)(exchange.review)
// isoFromExchange: proptics.Iso[String,List[Char]] = proptics.Iso_$$anon$16@4c6f5ff7
Laws
AnIso
must satisfy all AnIsoLaws. These laws reside in the <a href="../../api/proptics/law/>proptics.law package.
All laws constructed from the reversibility law, which says that we can completely reverse the transformation.
import proptics.AnIso
// import proptics.AnIso
import cats.Eq
// import cats.Eq
import cats.instances.string._
// import cats.instances.string._
import cats.syntax.eq._
// import cats.syntax.eq._
val anIsoStringToList = AnIso[String, List[Char]](_.toList)(_.mkString)
// anIsoStringToList: proptics.Iso[String,List[Char]] = proptics.Iso_$$anon$16@4b898027
Source reversibility
def sourceReversibility[S: Eq, A](anIso: AnIso[S, A], s: S): Boolean =
anIso.review(iso.view(s)) === s
sourceReversibility(anIsoStringToList, "Proptics")
// res0: Boolean = true
Focus reversibility
def focusReversibility[S, A: Eq](anIso: AnIso[S, A], a: A): Boolean =
anIso.view(iso.review(a)) === a
focusReversibility(anIsoStringToList, "Proptics".toList)
// res1: Boolean = true