Last active
April 27, 2016 15:37
-
-
Save cranst0n/04582e26b5dacf80a5e6 to your computer and use it in GitHub Desktop.
This file contains 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
package freedom | |
import java.awt.{ Color, Graphics2D } | |
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[RenderingOp, InteractOrLog, A] | |
def drawText(text: String)(implicit R: Rendering[App], I: Interaction[App], L: Logging[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 () | |
} | |
val img = new BufferedImage(250, 250, BufferedImage.TYPE_INT_RGB) | |
// Be sure to annotate the types | |
val x: InteractOrLog ~> Id = DefaultInterpreter or ConsoleInterpreter | |
val interpreter: App ~> Id = new GInterpreter(img.createGraphics()) or x | |
drawText("Hello Free!") foldMap interpreter | |
// 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