Created
September 1, 2017 18:37
-
-
Save arjunswaj/4c3c7789ccdd9f832f2cf16690b57cbf to your computer and use it in GitHub Desktop.
Free Monads with Errors
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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))