Skip to content

Instantly share code, notes, and snippets.

@Leammas
Created February 3, 2017 10:50
Show Gist options
  • Save Leammas/208f7f9d4e21cbaea6772275844b75c7 to your computer and use it in GitHub Desktop.
Save Leammas/208f7f9d4e21cbaea6772275844b75c7 to your computer and use it in GitHub Desktop.
import cats.data.Coproduct
import cats.free.{Free, Inject}
import cats.{Id, ~>}
object another extends App {
sealed trait CRUD[A]
case class Create(a: Foo) extends CRUD[Int]
case class Read(id: Int) extends CRUD[Foo]
case class Update(a: Foo) extends CRUD[Unit]
case class Delete(id: Int) extends CRUD[Unit]
case class Foo(id: Int, content: String)
class CrudActions[F[_]](implicit I: Inject[CRUD, F]) {
def create(a: Foo) = Free.inject[CRUD, F](Create(a))
def read(id: Int) = Free.inject[CRUD, F](Read(id))
def update(a: Foo) = Free.inject[CRUD, F](Update(a))
def delete(id: Int) = Free.inject[CRUD, F](Delete(id))
}
object CrudActions {
implicit def crud[F[_]](implicit I: Inject[CRUD, F]): CrudActions[F] = new CrudActions[F]
}
sealed trait Sum[A]
case class ConcatFoo(a: Foo, b: Foo) extends Sum[Foo]
case class SumFoo(a: Foo, b: Foo) extends Sum[Foo]
class SumActions[F[_]](implicit I: Inject[Sum, F]) {
def concat(a: Foo, b: Foo) = Free.inject[Sum, F](ConcatFoo(a, b))
def sum(a: Foo, b: Foo) = Free.inject[Sum, F](SumFoo(a, b))
}
object SumActions {
implicit def suma[F[_]](implicit I: Inject[Sum, F]): SumActions[F] = new SumActions[F]
}
type FooApp[A] = Coproduct[CRUD, Sum, A]
def program(implicit cp: CrudActions[FooApp], sp: SumActions[FooApp]): (Foo) => Free[FooApp, List[Foo]] = f => {
import cp._
import sp._
for {
id <- create(f)
created <- read(id)
_ <- update(created.copy(content = "bar"))
updated <- read(id)
concated <- concat(created, updated)
summed <- sum(created, updated)
} yield List(concated, summed)
}
object InterpreterId extends (CRUD ~> Id) {
var store = Map.empty[Int, Foo]
var ai = 1
def apply[A](fa: CRUD[A]): Id[A] = fa match {
case Create(a) =>
val aId = a.copy(id = ai)
store = store + (ai -> aId)
ai = ai + 1
aId.id
case Read(id) =>
store(id)
case Update(a) =>
store = store.updated(a.id, a)
()
case Delete(id) =>
store = store - id
()
}
}
object ISumId extends (Sum ~> Id) {
def apply[A](fa: Sum[A]): Id[A] = fa match {
case ConcatFoo(a, b) => Foo(a.id, a.content + b.content)
case SumFoo(a, b) => Foo(a.id + b.id, a.content)
}
}
val interpreter: FooApp ~> Id = InterpreterId or ISumId
val toRun = program(CrudActions.crud, SumActions.suma)(Foo(-100, "content"))
assert {
toRun.foldMap(interpreter) == List(Foo(1, "contentbar"), Foo(2, "content"))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment