Skip to content

Instantly share code, notes, and snippets.

@regiskuckaertz
Created May 17, 2018 07:02
Show Gist options
  • Save regiskuckaertz/334fa76da70dbd4b7d13a58e9d3ee24e to your computer and use it in GitHub Desktop.
Save regiskuckaertz/334fa76da70dbd4b7d13a58e9d3ee24e to your computer and use it in GitHub Desktop.
package example
import cats._
import cats.free._
import cats.data._
import cats.syntax.flatMap._
import cats.effect.{LiftIO, IO}
object Example {
import functors._
import stacks._
import cats.data.Tuple2K._
type Effect[A] = EitherK[Logging, Persist, A]
type Interp[A] = Tuple2K[CoLogging, CoPersist, A]
def prog(implicit L: Logs[Effect], P: Persists[Effect]): Free[Effect, Unit] =
P.store("bar") >> L.log("foo")
def interpretEffect(implicit CL: CoLogs[IO], CP: CoPersists[IO]): Cofree[Interp, IO[Unit]] =
Cofree.unfold(IO.pure(())) { a: IO[Unit] => Tuple2K(CoLogging(CL.coLog(a)), CoPersist(CP.coPersist(a))) }
}
/////////////////// FREE STUFF
case class Logging[A](msg: String, action: A)
case class Persist[A](msg: String, action: A)
class Logs[F[_]](implicit I: InjectK[Logging, F]) {
def log(msg: String): Free[F, Unit] = Free.inject[Logging, F](Logging(msg, ()))
}
class Persists[F[_]](implicit I: InjectK[Persist, F]) {
def store(msg: String): Free[F, Unit] = Free.inject[Persist, F](Persist(msg, ()))
}
/////////////////// COFREE STUFF
case class CoLogging[A](run: String => A)
case class CoPersist[A](run: String => A)
class CoLogs[F[_]: FlatMap](implicit L: LiftIO[F]) {
def coLog(f: F[Unit])(msg: String): F[Unit] = f >> L.liftIO(IO {
println(msg)
})
}
class CoPersists[F[_]: FlatMap](implicit L: LiftIO[F]) {
def coPersist(f: F[Unit])(msg: String): F[Unit] = f >> L.liftIO(IO {
println(s"storing $msg")
})
}
/////////////////// TYPECLASS INSTANCES
object functors {
implicit val fLogging = new Functor[Logging] {
def map[A, B](fa: Logging[A])(f: A => B) = Logging(fa.msg, f(fa.action))
}
implicit val fPersist = new Functor[Persist] {
def map[A, B](fa: Persist[A])(f: A => B) = Persist(fa.msg, f(fa.action))
}
implicit val fCoLogging = new Functor[CoLogging] {
def map[A, B](fa: CoLogging[A])(f: A => B) = CoLogging(fa.run andThen f)
}
implicit val fCoPersist = new Functor[CoPersist] {
def map[A, B](fa: CoPersist[A])(f: A => B) = CoPersist(fa.run andThen f)
}
}
object stacks {
implicit def liftCoLogs[F[_]: FlatMap](implicit L: LiftIO[F]) = new CoLogs[F]
implicit def liftCoPersists[F[_]: FlatMap](implicit L: LiftIO[F]) = new CoPersists[F]
implicit def liftLogging[F[_]](implicit I: InjectK[Logging, F]) = new Logs[F]
implicit def liftPersist[F[_]](implicit I: InjectK[Persist, F]) = new Persists[F]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment