Skip to content

Instantly share code, notes, and snippets.

@afsalthaj
Last active September 4, 2018 03:52
Show Gist options
  • Save afsalthaj/4f2d666894a9f79dc0458ab390dc3d84 to your computer and use it in GitHub Desktop.
Save afsalthaj/4f2d666894a9f79dc0458ab390dc3d84 to your computer and use it in GitHub Desktop.
package com.telstra.dxmodel.api.interop
import cats.data.{EitherT, Writer, WriterT}
import cats.free.Free
import scala.util.Try
import cats.implicits._
import cats.{Monad, ~>}
import com.telstra.dxmodel.api.interop
import scalaz.zio.IO
import com.telstra.dxmodel.instances.AllMonadInstances._
sealed trait Alg[_]
object Alg {
type Action[A] = Free[Alg, A]
case object Action1 extends Alg[Int]
case object Action2 extends Alg[Int]
type ZIO[A] = IO[Nothing, A]
type ActionWithLog[A] = WriterT[ZIO, String, A]
type SafeActionWithLog[A] = EitherT[ActionWithLog, String, A]
object SafeActionWithLog {
def apply[A](f: => IO[String, A], msg: String): SafeActionWithLog[A] = {
EitherT[ActionWithLog, String, A] { WriterT[ZIO, String, Either[String, A]](f.attempt.map(t => (msg, t))) }
}
}
def action1: Action[Int] = Action1.asAction
def action2: Action[Int] = Action2.asAction
val interpreter: Alg ~> SafeActionWithLog = new (Alg ~> SafeActionWithLog){
override def apply[A](fa: Alg[A]): SafeActionWithLog[A] = fa match {
case Action1 => SafeActionWithLog(IO.point(1), "Getting 1")
case Action2 => SafeActionWithLog(IO.fail("painful error"), "Failed")
}
}
def blaInterpreter(x: Alg ~> SafeActionWithLog) = new (Action ~> SafeActionWithLog) {
override def apply[A](fa: Action[A]): SafeActionWithLog[A] =
fa.foldMap(x)
}
}
object Logger {
import Alg._
type Logger[A] = WriterT[Action, List[String], A]
object Logger {
def apply[A](msg: String, f: Action[A]): Logger[A] =
WriterT(f.map(t => (List(msg), t)))
}
implicit def toLoggerOps[T](x: Either[Throwable, T]) = LoggerOps(x)
}
final case class LoggerOps[T](val underlying: Either[Throwable, T]) extends AnyVal {
def ||>(msg: String) =
WriterT(
IO.point ((
List(msg),
underlying
))
)
}
object Main extends App {
import Logger._
import Alg._
// Free algebra version. Looks nicer !
val z: Free[Alg, Unit] =
for {
_ <- action1
_ <- action1
_ <- action1
_ <- action1
_ <- action1
_ <- action2
} yield ()
val k= z.foldMap(interpreter).value.run.asIO.unsafeRunSync()
println(k)
// Result: Left(painful error)
// Finally tagless version - Oh oh!
val r = for {
_ <- EitherT { 4.asRight[Throwable] ||> "Getting 4" }
_ <- EitherT { 5.asRight[Throwable] ||> "Getting 5" }
_ <- EitherT { new Exception("Failed 1").asLeft[Int] ||> "Getting 6" }
_ <- EitherT { new Exception("Failed 2").asLeft[Int] ||> "Getting 7" }
} yield ()
println(r.value.run.asIO.unsafeRunSync())
// Result: (List(Getting 4, Getting 5, Getting 6),Left(java.lang.Exception: Failed 1))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment