An implementation of Software Transactional Memory for Cats Effect, inspired by Beautiful Concurrency.
For more information, see the documentation.
libraryDependencies += "io.github.timwspence" %% "cats-stm" % "0.6.0"
The core abstraction is the TVar
(transactional var), which exposes operations in the
STM
monad. Once constructed, STM
actions can be atomically evaluated in the IO
monad.
import cats.effect.{ExitCode, IO, IOApp}
import io.github.timwspence.cats.stm.{TVar, STM}
object Main extends IOApp {
override def run(args: List[String]): IO[ExitCode] = for {
accountForTim <- TVar.of[Long](100).commit[IO]
accountForSteve <- TVar.of[Long](0).commit[IO]
_ <- printBalances(accountForTim, accountForSteve)
_ <- giveTimMoreMoney(accountForTim).start
_ <- transfer(accountForTim, accountForSteve)
_ <- printBalances(accountForTim, accountForSteve)
} yield ExitCode.Success
private def transfer(accountForTim: TVar[Long], accountForSteve: TVar[Long]): IO[Unit] = for {
_ <- STM.atomically[IO] {
for {
balance <- accountForTim.get
_ <- STM.check(balance > 100)
_ <- accountForTim.modify(_ - 100)
_ <- accountForSteve.modify(_ + 100)
} yield ()
}
} yield ()
private def giveTimMoreMoney(accountForTim: TVar[Long]): IO[Unit] = for {
_ <- IO(Thread.sleep(5000))
_ <- STM.atomically[IO](accountForTim.modify(_ + 1))
} yield ()
private def printBalances(accountForTim: TVar[Long], accountForSteve: TVar[Long]): IO[Unit] = for {
_ <- accountForTim.get.commit[IO].flatMap(b => IO(println(s"Tim: $b")))
_ <- accountForSteve.get.commit[IO].flatMap(b => IO(println(s"Tim: $b")))
} yield ()
}
The documentation is built using sbt microsites. You
can generate it via sbt makeMicrosite
. You can view it locally via cd docs/target/site && jekyll serve
.
This software was inspired by Beautiful Concurrency and informed by ZIO which has a common origin in that paper via the stm package.