Skip to content

Instantly share code, notes, and snippets.

@arjunswaj
Created September 1, 2017 18:37
Show Gist options
  • Save arjunswaj/4c3c7789ccdd9f832f2cf16690b57cbf to your computer and use it in GitHub Desktop.
Save arjunswaj/4c3c7789ccdd9f832f2cf16690b57cbf to your computer and use it in GitHub Desktop.
Free Monads with Errors
package com.asb.free
import cats.data.{EitherK, EitherT}
import cats.free.Free
import cats.free.Free.inject
import cats.{Id, InjectK, ~>}
/**
* Program With Errors.
* Created by arjun on 9/1/17.
*/
object ProgramWithErrors {
case class Employee(name: String, managerId: Long, id: Long)
case class Address(line1: String, line2: String, country: String)
sealed trait EmployeeAction[R]
case class GetEmployee(id: Long) extends EmployeeAction[Either[Exception, Employee]]
case class EmployeeIdByName(name: String) extends EmployeeAction[Long]
class EmployeeActions[F[_]](implicit I: InjectK[EmployeeAction, F]) {
type GetEmployeeF[A] = Free[F, A]
def getEmployeeIdByName(name: String): Free[F, Long] =
inject(EmployeeIdByName(name))
def getEmployee(id: Long): GetEmployeeF[Either[Exception, Employee]] =
inject(GetEmployee(id))
}
object EmployeeActions {
def apply[F[_]](implicit I: InjectK[EmployeeAction, F]): EmployeeActions[F] = new EmployeeActions[F]
}
object EmployeeInterpreter extends (EmployeeAction ~> Id) {
override def apply[A](fa: EmployeeAction[A]): Id[A] = fa match {
case GetEmployee(id) =>
if (id == 1L) Right(Employee("Arjun", 11L, 1L))
else if (id == 2L) Right(Employee("Aditya", 11L, 2L))
else Left(new Exception("No such employee exists"))
case EmployeeIdByName(name) =>
name match {
case "Arjun" => 1L
case "Aditya" => 2L
case _ => 0L
}
}
}
sealed trait ContactAction[R]
case class GetAddress(empId: Long) extends ContactAction[Either[Exception, Address]]
class ContactActions[F[_]](implicit I: InjectK[ContactAction, F]) {
type GetAddressF[A] = Free[F, A]
def getAddress(id: Long): GetAddressF[Either[Exception, Address]] =
inject(GetAddress(id))
}
object ContactActions {
def apply[F[_]](implicit I: InjectK[ContactAction, F]): ContactActions[F] = new ContactActions[F]
}
object ContactInterpreter extends (ContactAction ~> Id) {
override def apply[A](fa: ContactAction[A]): Id[A] = fa match {
case GetAddress(id) =>
if (id == 1L) Right(Address("Vijayanagar", "Bangalore", "India"))
else if (id == 11L) Right(Address("CP", "Delhi", "India"))
else Left(new Exception("No Address exists"))
}
}
type Program[A] = EitherK[EmployeeAction, ContactAction, A]
def findManagerAddress(name: String)
(implicit EA: EmployeeActions[Program],
CA: ContactActions[Program]): Free[Program, Address] = {
import CA._
import EA._
val address: Free[Program, Address] = for {
employeeId <- getEmployeeIdByName(name)
employee <- EitherT(getEmployee(employeeId))
managerAddress <- EitherT(getAddress(employee.managerId))
} yield managerAddress
address
}
def main(args: Array[String]): Unit = {
implicit val EA: EmployeeActions[Program] = EmployeeActions[Program]
implicit val CA: ContactActions[Program] = ContactActions[Program]
val interpreter: Program ~> Id = EmployeeInterpreter or ContactInterpreter
val res = findManagerAddress("Arjun").foldMap(interpreter)
println(res)
}
}
@arjunswaj
Copy link
Author

Error:(75, 16) type mismatch; found : cats.data.EitherT[EA.GetEmployeeF,Exception,com.asb.free.ProgramWithErrors.Address] required: cats.free.Free[com.asb.free.ProgramWithErrors.Program,com.asb.free.ProgramWithErrors.Address] employee <- EitherT(getEmployee(employeeId))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment