Last active
July 5, 2017 21:57
-
-
Save juanjovazquez/31cc992e42a91c08c6c01fb3b8e6a2b0 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
import cats.~> | |
import cats.data.State | |
import cats.syntax.all._ | |
import org.atnos.eff.{ |=, <=, Eff, Fx, Member } | |
import org.atnos.eff.state.get | |
import org.atnos.eff.either.fromEither | |
import org.atnos.eff.Eff.send | |
import org.atnos.eff.Interpret.translateNat | |
import org.atnos.eff.syntax.all._ | |
object EffPoC { | |
// model | |
case class Foo(id: Long) | |
case class Bar(id: Long) | |
case class MyError(msg: String) | |
// custom effects | |
sealed abstract class FooRepoEffect[A] | |
object FooRepoEffect { | |
type _fooRepo[R] = FooRepoEffect |= R | |
type _FooRepo[R] = FooRepoEffect <= R | |
case class FindById(id: Long) extends FooRepoEffect[Foo] | |
object syntax { | |
def findById[R: _fooRepo](id: Long): Eff[R, Foo] = | |
send(FindById(id)) | |
} | |
object interpreters { | |
import RepoImpls._ | |
def fromFooEffectToDBAction[R: _DBAction: _Error]: FooRepoEffect ~> Eff[R, ?] = | |
Lambda[FooRepoEffect ~> Eff[R, ?]] { | |
case FindById(id) => FooRepo.findById(id) | |
} | |
def runFooRepo[R, T, U](p: Eff[R, T])( | |
implicit M: Member.Aux[FooRepoEffect, R, U], | |
DB: _DBAction[U], | |
E: _Error[U] | |
): Eff[U, T] = translateNat(p)(fromFooEffectToDBAction) | |
} | |
implicit class FooRepoEffectOps[R, T, U](p: Eff[R, T]) { | |
import RepoImpls._ | |
def runFooRepo( | |
implicit M: Member.Aux[FooRepoEffect, R, U], | |
DB: _DBAction[U], | |
E: _Error[U] | |
): Eff[U, T] = interpreters.runFooRepo(p) | |
} | |
} | |
sealed abstract class BarRepoEffect[A] | |
object BarRepoEffect { | |
type _barRepo[R] = BarRepoEffect |= R | |
type _BarRepo[R] = BarRepoEffect <= R | |
case class FindById(id: Long) extends BarRepoEffect[Bar] | |
object syntax { | |
def findById[R: _barRepo](id: Long): Eff[R, Bar] = | |
send(FindById(id)) | |
} | |
object interpreters { | |
import RepoImpls._ | |
def fromBarEffectToDBAction[R: _DBAction: _Error]: BarRepoEffect ~> Eff[R, ?] = | |
Lambda[BarRepoEffect ~> Eff[R, ?]] { | |
case FindById(id) => BarRepo.findById(id) | |
} | |
def runBarRepo[R, T, U](p: Eff[R, T])( | |
implicit M: Member.Aux[BarRepoEffect, R, U], | |
DB: _DBAction[U], | |
E: _Error[U] | |
): Eff[U, T] = translateNat(p)(fromBarEffectToDBAction) | |
} | |
implicit class BarRepoEffectOps[R, T, U](p: Eff[R, T]) { | |
import RepoImpls._ | |
def runBarRepo( | |
implicit M: Member.Aux[BarRepoEffect, R, U], | |
DB: _DBAction[U], | |
E: _Error[U] | |
): Eff[U, T] = interpreters.runBarRepo(p) | |
} | |
} | |
object RepoImpls { | |
type Foos = Map[Long, Foo] | |
type Bars = Map[Long, Bar] | |
case class DB(foos: Foos, bars: Bars) | |
val initialDB = DB(Map.empty[Long, Foo], Map.empty[Long, Bar]) | |
type DBAction[A] = State[DB, A] | |
type _dbAction[R] = DBAction |= R | |
type _DBAction[R] = DBAction <= R | |
type Error[A] = MyError Either A | |
type _error[R] = Error |= R | |
type _Error[R] = Error <= R | |
object FooRepo { | |
def findById[R: _dbAction: _error](id: Long): Eff[R, Foo] = | |
for { | |
foo <- get.map(_.foos.get(id)) | |
r <- fromEither(foo.fold(MyError("Not Found").asLeft[Foo])(_.asRight)) | |
} yield r | |
} | |
object BarRepo { | |
def findById[R: _dbAction: _error](id: Long): Eff[R, Bar] = | |
for { | |
bar <- get.map(_.bars.get(id)) | |
r <- fromEither(bar.fold(MyError("Not Found").asLeft[Bar])(_.asRight)) | |
} yield r | |
} | |
} | |
import RepoImpls._ | |
type Stack = Fx.fx4[FooRepoEffect, BarRepoEffect, DBAction, Error] | |
def runAll[A](p: Eff[Stack, A]): (Error[A], DB) = | |
p.runFooRepo.runBarRepo.runEither.runState(initialDB).run | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment