Last active
February 26, 2019 14:10
-
-
Save mmenestret/6ad7d8395ec070f03d623d4522e48a0c to your computer and use it in GitHub Desktop.
Tagless final -> Explicit dependencies passing -> ReaderT
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
object BoilerPlate { | |
// Some random effect type classes we'll want to stack (MTL) | |
trait IOEffect[F[_]] | |
trait StateEffect[F[_]] | |
// Our "final" type that match our needs, providing the typeclass instances needed by our algebras implementations | |
// It's often a monad transformer stack or custom type classes implementations | |
type MyF[A] | |
implicit def myFIO: IOEffect[MyF] = ??? | |
implicit def myFState: StateEffect[MyF] = ??? | |
// Our business domain algebras | |
trait Alg1[F[_]] { | |
def ope1[A]: F[A] | |
} | |
trait Alg2[F[_]] { | |
def ope2[A]: F[A] | |
} | |
} | |
object TaglessFinal { | |
import BoilerPlate._ | |
// Our MTL algebras interpreters | |
implicit def implAlg1[F[_]: IOEffect]: Alg1[F] = ??? | |
implicit def implAlg2[F[_]: StateEffect]: Alg2[F] = ??? | |
// Our program, using type classes encoding to provide our interpreters | |
def program[F[_]: Alg1[F]: Alg2[F]](): F[Unit] = ??? | |
program[MyF]() // Go | |
} | |
object ExplicitEncoding { | |
import BoilerPlate._ | |
// Our algebras interpreters | |
final case class ImplAlg1[F[_]: IOEffect]() extends Alg1[F] { def ope1[A]: F[A] = ??? } | |
final case class ImplAlg2[F[_]: StateEffect]() extends Alg2[F] { def ope2[A]: F[A] = ??? } | |
// Our program that takes it's dependencies explicitly (and does not rely on type class encoding) | |
def program[F[_]](alg1: Alg1[F], alg2: Alg2[F]): F[Unit] = ??? | |
program[MyF](ImplAlg1(), ImplAlg2()) // Go | |
} | |
object ReaderTEncoding { | |
import BoilerPlate._ | |
final case class ImplAlg1[F[_]: IOEffect]() extends Alg1[F] { def ope1[A]: F[A] = ??? } | |
final case class ImplAlg2[F[_]: StateEffect]() extends Alg2[F] { def ope2[A]: F[A] = ??? } | |
final case class Env[F[_]]( | |
alg1: ImplAlg1[F], | |
alg2: ImplAlg2[F] | |
) | |
// Every time needed, providing dependencies explicitly is cumbersome. | |
// Let's pack them "all together" in a `Env` record of functions | |
// and define ReaderT[Env, F, ?] functions so we can provide `Env` later | |
def program[F[_]]: ReaderT[F, Env, Unit] = ??? | |
val myProdEnv: Env[MyF] = Env(ImplAlg1[MyF](), ImplAlg2[MyF]()) | |
program[MyF].run(myProdEnv) // Go | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment