Skip to content

Instantly share code, notes, and snippets.

@kciesielski
Last active April 12, 2019 00:09
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save kciesielski/27b53055efbb0fe0188f to your computer and use it in GitHub Desktop.
Save kciesielski/27b53055efbb0fe0188f to your computer and use it in GitHub Desktop.
Free Monads example
package com.softwaremill.freemonads
import cats.free.Free
import cats.~>
import cats._, cats.std.all._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
sealed trait External[A]
case class Tickets(count: Int) extends AnyVal
case class InvokeTicketingService(count: Int) extends External[Tickets]
case class UserTicketsRequest(ticketCount: Int)
object GetTicketsExample {
def purchaseTickets(input: UserTicketsRequest): Free[External, Option[Tickets]] = {
if (input.ticketCount > 0) {
// creates a "Suspend" node
Free.liftF(InvokeTicketingService(input.ticketCount)).map(Some(_))
} else {
Free.pure(None)
}
}
def bonusTickets(purchased: Option[Tickets]): Free[External, Option[Tickets]] = {
if (purchased.exists(_.count > 10)) {
Free.liftF(InvokeTicketingService(1)).map(Some(_))
} else {
Free.pure(None)
}
}
def formatResponse(purchased: Option[Tickets], bonus: Option[Tickets]): String =
s"Purchased tickets: $purchased, bonus: $bonus"
val input = UserTicketsRequest(11)
val logic: Free[External, String] = for {
purchased <- purchaseTickets(input)
bonus <- bonusTickets(purchased)
} yield formatResponse(purchased, bonus)
val externalToServiceInvoker = new (External ~> Future) {
override def apply[A](e: External[A]): Future[A] = e match {
case InvokeTicketingService(c) => serviceInvoker.run(s"/tkts?count=$c")
}
}
val result = logic.foldMap(externalToServiceInvoker)
result.foreach(println)
object serviceInvoker {
def run(path: String) = {
Future {
Tickets(11)
}
}
}
}
@prayagupa
Copy link

prayagupa commented Jun 19, 2018

hi @kciesielski can you please mention the cat dependencies required for above code snippet as well?

I could not find cats.std.all._ in following dependencies,

libraryDependencies += "org.typelevel" %% "cats" % "0.9.0"
libraryDependencies += "org.typelevel" %% "cats-core" % "1.1.0"
libraryDependencies += "org.typelevel" %% "cats-free" % "1.1.0"
libraryDependencies += "org.typelevel" %% "cats-effect" % "0.10"
libraryDependencies += "org.typelevel" %% "alleycats-core" % "1.1.0"

I found alleycats.std.all._ but not sure if thats correct. I get following compilation error

[error] /Users/prayagupd/buybest/learnyouascala.fm/9_error_handling/src/test/scala/FreeMonad.scala:103:29: could not find implicit value for parameter M: cats.Monad[scala.concurrent.Future]
[error]   val result = logic.foldMap(externalToServiceInvoker)
[error]                             ^
[error] three errors found
[error] (test:compileIncremental) Compilation failed
[error] Total time: 6 s, completed Jun 18, 2018 10:18:56 PM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment