Skip to content

Instantly share code, notes, and snippets.

@programaker
Last active May 31, 2021 08:38
Show Gist options
  • Save programaker/51c31e8c1ca3d4715b872d610c1a636c to your computer and use it in GitHub Desktop.
Save programaker/51c31e8c1ca3d4715b872d610c1a636c to your computer and use it in GitHub Desktop.
Scala 3 context functions
import cats.Monad
import cats.syntax.functor.*
import cats.effect.IO
import cats.effect.unsafe.implicits.global
case class Frunfles(id: Long, name: String)
trait DatabaseConnection:
def exec[F[_]: Monad](op: String): F[Unit]
object DatabaseConnection:
given DatabaseConnection with
def exec[F[_]: Monad](op: String): F[Unit] = Monad[F].pure(println(s">>> DB op = $op"))
// single-dependency "primitive" environments
type MonadEnv[F[_], A] = Monad[F] ?=> F[A]
type DatabaseEnv[A] = DatabaseConnection ?=> A
// composing envs by nesting
// both are equivalent!
type Env[F[_], A] = MonadEnv[F, DatabaseEnv[A]]
type Env2[F[_], A] = DatabaseEnv[MonadEnv[F, A]]
// multi-dependency environments
// both are equivalent!
type Env3[F[_], A] = (DatabaseConnection, Monad[F]) ?=> F[A]
type Env4[F[_], A] = (Monad[F], DatabaseConnection) ?=> F[A]
// need "Env"
def findAllFrunfles[F[_]]: Env[F, List[Frunfles]] =
summon[DatabaseConnection].exec("findAll").map(_ => List.empty)
def findFrunflesById[F[_]](id: Long): Env[F, Option[Frunfles]] =
summon[DatabaseConnection].exec("findById").map(_ => None)
// need "Env2"
def insertFrunfles[F[_]](f: Frunfles): Env2[F, Unit] =
summon[DatabaseConnection].exec("insert")
// need "Env3"
def updateFrunfles[F[_]](f: Frunfles): Env3[F, Unit] =
summon[DatabaseConnection].exec("update")
// need "Env4"
def deleteFrunfles[F[_]](id: Long): Env4[F, Unit] =
summon[DatabaseConnection].exec("delete")
// nesting order does not matter!
// parameter order does not matter!
// mixing different envs does not matter!
// the functions are called as if the envs don't exist at all!
val io: IO[Unit] =
for
_ <- insertFrunfles[IO](Frunfles(1L, "frunfles"))
_ <- findFrunflesById[IO](1L)
_ <- updateFrunfles[IO](Frunfles(1L, "sbrubbles"))
_ <- deleteFrunfles[IO](1L)
yield ()
val res1 = io.unsafeRunSync()
val res2 = findAllFrunfles[IO].unsafeRunSync()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment