Skip to content

Instantly share code, notes, and snippets.

@yasuabe
Created December 19, 2017 06:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yasuabe/fdb780d6c533603c25694a75aeea3cbb to your computer and use it in GitHub Desktop.
Save yasuabe/fdb780d6c533603c25694a75aeea3cbb to your computer and use it in GitHub Desktop.
by free monad
import cats.data.StateT
import cats.effect.IO
import cats.free.Free
import cats.free.Free.liftF
import cats.{Id, ~>}
import cats.instances.vector._
import cats.syntax.foldable._
sealed trait Console[A]
case class PrintLn(s: String) extends Console[Unit]
type ConsoleF[T] = Free[Console, T]
def printLn(s: String): ConsoleF[Unit] = liftF(PrintLn(s))
case class CashRegister(total: Int) {
def addCash(toAdd: Int) = CashRegister(total + toAdd)
}
type Purchase = CashRegister => ConsoleF[CashRegister]
def makePurchase(amount: Int): Purchase = r => for {
_ <- printLn(s"Purchase in amount: $amount")
} yield r addCash amount
type PurchaseHistory = Vector[Purchase]
def execute(p: Purchase): StateT[ConsoleF, (PurchaseHistory, CashRegister), Unit] =
StateT { case (h, r) => p(r) map { r2 => ((h :+ p, r2), ()) }}
// test -------------------------------------------------------------------
val p1 = makePurchase(100)
val p2 = makePurchase(50)
def freeProgram = (for {
_ <- execute(p1)
_ <- execute(p2)
} yield ()).runS((Vector.empty, CashRegister(0)))
def ioCompiler: (Console ~> IO) = new (Console ~> IO) {
override def apply[A](fa: Console[A]): IO[A] = fa match {
case PrintLn(text) => IO { println(text) }
}
}
val (history, last) = freeProgram.foldMap(ioCompiler).unsafeRunSync()
// 再実行
def idCompiler: (Console ~> Id) = new (Console ~> Id) {
override def apply[A](fa: Console[A]): Id[A] = fa match {
case PrintLn(text) => println(text); ()
}
}
history.foldLeftM(CashRegister(10))((b, p) => p(b)).foldMap(idCompiler)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment