Skip to content

Instantly share code, notes, and snippets.

trait Restaurant {
def menu: String
}
case class Mexican() extends Restaurant {
def menu: String = "tacos"
}
case class Italian() extends Restaurant {
def menu: String = "spaghetti"
def main(): IO[(Vector[SystemState], SystemState)] = {
for {
monadReader <- createMonadReader(Env("127.0.0.1:8080"))
monadWriter <- createMonadWriter[Vector[SystemState]]
monadState <- createMonadState(SystemState(Map.empty[Env, Status]))
result <- program(monadReader, monadWriter, monadState)
} yield result
}
def program[F[_]](R: MonadReader[F, Env],
W: MonadWriter[F, Vector[SystemState]],
S: MonadState[F, SystemState]): F[(Vector[SystemState], SystemState)] = {
implicit val M: Monad[F] = R.monad
for {
status <- R.reader(getServerStatus[F]())
state <- S.get
def createMonadWriter[L](implicit M: Monoid[L]): IO[MonadWriter[IO, L]] = {
for {
writer <- Ref.of[IO, L](M.empty)
} yield new MonadWriter[IO, L] {
val monad: Monad[IO] = Monad[IO]
def tell(l: L): IO[Unit] = writer.update(_.combine(l))
def logs: IO[L] = writer.get
}
}
trait MonadWriter[F[_], L] {
val monad: Monad[F]
def tell(l: L): F[Unit]
def logs: F[L]
}
trait MonadState[F[_], S] {
val monad: Monad[F]
program[IO].run(Env("127.0.0.1:8080"), SystemState(Map.empty[Env, Status])) // IO[(Vector[SystemState], SystemState, SystemState)]
def program[F[_]](implicit M: Monad[F]): IndexedReaderWriterStateT[F, Env, Vector[SystemState], SystemState, SystemState, SystemState] = {
for {
// retrieve environment input
env <- IndexedReaderWriterStateT.ask[F, Env, Vector[SystemState], SystemState]
// get server status as F[Status] and lift into transformer context
statusF = getServerStatus[F]().apply(env)
status <- IndexedReaderWriterStateT.liftF[F, Env, Vector[SystemState], SystemState, Status](statusF)
// get current state
final class IndexedReaderWriterStateT[F[_], E, L, SA, SB, A](val runF: F[(E, SA) => F[(L, SB, A)]]) {
def map[B](f: A => B)(implicit F: Functor[F]): IndexedReaderWriterStateT[F, E, L, SA, SB, B] = {
transform { (l, s, a) => (l, s, f(a)) }
}
def transform[LL, SC, B](f: (L, SB, A) => (LL, SC, B))
(implicit F: Functor[F]): IndexedReaderWriterStateT[F, E, LL, SA, SC, B] = {
IndexedReaderWriterStateT.applyF {
F.map(runF) { rwsfa =>
sealed trait Status
case object Healthy extends Status
case object Degraded extends Status
case object Unavailable extends Status
case class Env(serverUrl: String)
case class SystemState(value: Map[Env, Status])
def getServerStatus[F[_]](): Env => F[Status] = ???
def alertAdmin[F[_]](status: Status): Env => F[Unit] = ???
def program(R: MonadReader[IO, Config]): IO[Unit] = {
for {
status <- R.reader(getJobStatus)
_ <- R.reader(sendAlert(status))
} yield ()
}