Last active
January 2, 2022 02:41
-
-
Save kailuowang/7377633fd8cf691834eb2130afe8c129 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
trait IsoK[F[_], G[_]] { self => | |
def from[A](fa: F[A]): G[A] | |
def to[A](ga: G[A]): F[A] | |
def flip: IsoK[G, F] = new IsoK[G, F] { | |
def from[A](ga: G[A]): F[A] = self.to(ga) | |
def to[A](fa: F[A]): G[A] = self.from(fa) | |
} | |
def compose[H[_]](that: IsoK[G, H]): IsoK[F, H] = new IsoK[F, H]{ | |
def from[A](fa: F[A]): H[A] = that.from(self.from(fa)) | |
def to[A](ha: H[A]): F[A] = self.to(that.to(ha)) | |
} | |
//convenient shortcut method | |
implicit def monad(implicit F: Monad[F]): Monad[G] = IsoK.monad[F, G](F, this) | |
implicit def applicative(implicit F: Applicative[F]): Applicative[G] = IsoK.applicative[F, G](F, this) | |
} | |
object IsoK extends IsoInstances with IsoProvidedInstances { | |
def apply[F[_], G[_]](implicit inst: IsoK[F, G]): IsoK[F, G] = inst | |
} | |
trait IsoInstances { | |
implicit def optionT[F[_]]: IsoK[OptionT[F, *], Lambda[A => F[Option[A]]]] = new IsoK[OptionT[F, *], Lambda[A => F[Option[A]]]] { | |
def from[A](fa: OptionT[F, A]): F[Option[A]] = fa.value | |
def to[A](ga: F[Option[A]]): OptionT[F, A] = OptionT(ga) | |
} | |
} | |
sealed private[cats] trait IsoProvidedInstances { | |
def applicative[F[_], G[_]](implicit F: Applicative[F], I: IsoK[F, G]): Applicative[G] = | |
new Applicative[G] { | |
import I._ | |
def pure[A](r: A): G[A] = from(F.pure(r)) | |
override def map[A, B](ga: G[A])(f: A => B): G[B] = | |
from(F.map(to(ga))(f)) | |
override def map2[A, B, C](ga: G[A], gb: G[B])(fn: (A, B) => C): G[C] = | |
from(F.map2(to(ga), to(gb))(fn)) | |
override def product[A, B](ga: G[A], gb: G[B]): G[(A, B)] = | |
from(F.product(to(ga), to(gb))) | |
def ap[A, B](f: G[A => B])(ga: G[A]): G[B] = | |
from(F.ap(to(f))(to(ga))) | |
} | |
def monad[F[_], G[_]](implicit F: Monad[F], I: IsoK[F, G]): Monad[G] = | |
new Monad[G] { | |
import I._ | |
def pure[A](r: A): G[A] = from(F.pure(r)) | |
def flatMap[A, B](ga: G[A])(f: A => G[B]): G[B] = | |
from(F.flatMap(to(ga))(f.map(to))) | |
override def map[A, B](ga: G[A])(f: A => B): G[B] = | |
from(F.map(to(ga))(f)) | |
override def map2[A, B, C](ga: G[A], gb: G[B])(fn: (A, B) => C): G[C] = | |
from(F.map2(to(ga), to(gb))(fn)) | |
override def product[A, B](ga: G[A], gb: G[B]): G[(A, B)] = | |
from(F.product(to(ga), to(gb))) | |
override def ap[A, B](f: G[A => B])(ga: G[A]): G[B] = | |
from(F.ap(to(f))(to(ga))) | |
def tailRecM[A, B](a: A)(fn: A => G[Either[A, B]]): G[B] = | |
from(F.tailRecM(a)(fn.map(to))) | |
} | |
def distributive[F[_], G[_]](implicit F: Distributive[F], I: IsoK[F, G]): Distributive[G] = | |
new Distributive[G] { | |
import I._ | |
def map[A, B](ga: G[A])(f: A => B): G[B] = from(F.map(to(ga))(f)) | |
def distribute[H[_]: Functor, A, B](ha: H[A])(f: A => G[B]): G[H[B]] = | |
from(F.distribute(ha)(f.map(to))) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Basically this allows you to easily take advantage of the
Monad[Function1]
if you alg trait is basically aA=>B
or Transformer such asOptionT
orNested
, if your alg trait isA => T[B]