Skip to content

Instantly share code, notes, and snippets.

@tbrown1979
Forked from cranst0n/freedom.scala
Created March 3, 2016 19:21
Show Gist options
  • Save tbrown1979/74a545c5328a51578935 to your computer and use it in GitHub Desktop.
Save tbrown1979/74a545c5328a51578935 to your computer and use it in GitHub Desktop.
package freedom
import scala.collection.JavaConverters._
import java.awt.Color
import java.awt.image.BufferedImage
import cats.data.Coproduct
import cats.free.{ Free, Inject }
import cats.{ ~>, Id }
object Freedom extends App {
import interaction._
import logging._
import rendering._
type InteractOrLog[A] = Coproduct[InteractionOp, LoggingOp, A]
type App[A] = Coproduct[InteractOrLog, RenderingOp, A]
val img = new BufferedImage(250, 250, BufferedImage.TYPE_INT_RGB)
val g = img.createGraphics()
val interp = DefaultInterpreter or ConsoleInterpreter or new GInterpreter(g)
def drawText(text: String)(implicit I: Interaction[App], L: Logging[App], R: Rendering[App]) = {
import I._, R._, L._
for {
_ <- tell("here's a message")
_ <- setColor(Color.orange)
_ <- debug("set the color")
_ <- fillRect(25, 25, 50, 50)
_ <- debug("filled the rect")
_ <- setColor(Color.blue)
_ <- drawString(text, 10, 10)
_ <- debug(s"rendered: $text")
} yield ()
}
// Compilation Error
// [error] /home/brandy/workspace/freedom/src/main/scala/freedom/Minimal.scala:63: could not find implicit value for parameter I: freedom.interaction.Interaction[freedom.Freedom.App]
// [error] drawText("Hello Free!") foldMap interp
// [error] ^
// [error] one error found
drawText("Hello Free!") foldMap interp
// Dump the results for inspection
javax.imageio.ImageIO.write(img, "png", new java.io.File("/home/brandy/Desktop/free-image.png"))
}
object interaction {
sealed trait InteractionOp[A]
case class Tell(message: String) extends InteractionOp[Unit]
class Interaction[F[_]](implicit I: Inject[InteractionOp, F]) {
def tell(message: String) = Free.inject[InteractionOp, F](Tell(message))
}
object Interaction {
implicit def instance[F[_]](implicit I: Inject[InteractionOp, F]): Interaction[F] = new Interaction[F]
}
object DefaultInterpreter extends (InteractionOp ~> Id) {
def apply[A](fa: InteractionOp[A]): Id[A] = {
fa match {
case Tell(message) => println(message)
}
}
}
}
object logging {
sealed trait LoggingOp[A]
case class Debug(message: String) extends LoggingOp[Unit]
class Logging[F[_]](implicit I: Inject[LoggingOp, F]) {
def debug(message: String) = Free.inject[LoggingOp, F](Debug(message))
}
object Logging {
implicit def instance[F[_]](implicit I: Inject[LoggingOp, F]): Logging[F] = new Logging[F]
}
object ConsoleInterpreter extends (LoggingOp ~> Id) {
def apply[A](fa: LoggingOp[A]): Id[A] = {
fa match {
case Debug(message) => println(message)
}
}
}
}
object rendering {
import java.awt._
sealed trait RenderingOp[A]
case class FillRect(x: Int, y: Int, width: Int, height: Int) extends RenderingOp[Unit]
case class DrawString(str: String, x: Int, y: Int) extends RenderingOp[Unit]
case class SetColor(c: Color) extends RenderingOp[Unit]
class Rendering[F[_]](implicit I: Inject[RenderingOp, F]) {
def drawString(str: String, x: Int, y: Int) = Free.inject[RenderingOp, F](DrawString(str, x, y))
def fillRect(x: Int, y: Int, width: Int, height: Int) = Free.inject[RenderingOp, F](FillRect(x, y, width, height))
def setColor(c: Color) = Free.inject[RenderingOp, F](SetColor(c))
}
object Rendering {
implicit def instance[F[_]](implicit I: Inject[RenderingOp, F]): Rendering[F] = new Rendering[F]
}
class GInterpreter(g: Graphics2D) extends (RenderingOp ~> Id) {
def apply[A](fa: RenderingOp[A]): Id[A] = {
fa match {
case DrawString(str, x, y) => g.drawString(str, x, y)
case FillRect(x, y, width, height) => g.fillRect(x, y, width, height)
case SetColor(c) => g.setColor(c)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment