Last active
January 2, 2022 02:41
-
-
Save kailuowang/7377633fd8cf691834eb2130afe8c129 to your computer and use it in GitHub Desktop.
This file contains 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))) | |
} | |
} |
Basically this allows you to easily take advantage of the Monad[Function1]
if you alg trait is basically a A=>B
or Transformer such as OptionT
or Nested
, if your alg trait is A => T[B]
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://github.com/http4s/http4s/blob/main/core/shared/src/main/scala/org/http4s/FormDataDecoder.scala#L239
Instance of
FormDAtaDecoder
in Http4s can be written as follows