Skip to content

Instantly share code, notes, and snippets.

@ashic
Created June 6, 2016 22:07
Show Gist options
  • Select an option

  • Save ashic/345ef1136d2d7c707f20d062616d2f6c to your computer and use it in GitHub Desktop.

Select an option

Save ashic/345ef1136d2d7c707f20d062616d2f6c to your computer and use it in GitHub Desktop.
Free with futures and error handling
import Model._
import OpOps._
import cats.data.XorT
import cats.free.Free
import cats.~>
import scala.concurrent.{Await, ExecutionContext, Future}
object OpOps {
implicit def toFree[A](op:Op[A]) : Free[Op, A] =
Free.liftF(op)
}
object ProfileStore {
def load(id:Int)(implicit ec:ExecutionContext) : Future[Profile] = Future {
if(id == 42) throw new Exception("lala")
Profile(id, "someName")
}
def save(p:Profile)(implicit ec:ExecutionContext) : Future[Profile] = Future {p}
}
object Model {
sealed trait Op[A]
type AppResult[A] = XorT[Future, Throwable, A]
case class Profile(id:Int, name:String)
case class loadProfile(id:Int) extends Op[Profile]
case class saveProfile(p:Profile) extends Op[Profile]
case class log(msg:String) extends Op[Unit]
import cats.implicits._
import scala.concurrent.ExecutionContext.Implicits.global
val futureInterpreter = new (Op ~> AppResult) {
override def apply[A](fa: Op[A]): AppResult[A] = fa match {
case loadProfile(id) => ProfileStore.load(id).attemptT
case saveProfile(p:Profile) => ProfileStore.save(p).attemptT
case log(msg:String) => Future{println(msg)}.attemptT
}
}
def program(id:Int, newName:String): Free[Op, Profile] = for {
p <- loadProfile(id)
_ <- log(s"loaded profile with name ${p.name}")
p2 <- saveProfile(p.copy(name=newName))
_ <- log(s"saved profile with name ${p2.name}")
} yield p2
}
object MyApp2 extends App {
import scala.concurrent.ExecutionContext.Implicits.global
import cats.implicits._
import scala.concurrent.duration._
val p1f : XorT[Future, Throwable, Profile] = program(20, "john").foldMap(futureInterpreter)
val p1 = Await.result(p1f.value, 2 seconds)
println(p1) //prints Right[Profile]
val p2f : XorT[Future, Throwable, Profile] = program(42, "james").foldMap(futureInterpreter)
val p2 = Await.result(p2f.value, 2 seconds)
println(p2) //prints Left[Exception]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment