-
-
Save coltfred/975310ef8b8a06dcc18e to your computer and use it in GitHub Desktop.
This file contains hidden or 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 scala.collection.JavaConverters._ | |
import java.awt.{ Color, Graphics2D } | |
import java.awt.image.BufferedImage | |
import cats.data.{ Coproduct, Xor } | |
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 () | |
} | |
def interpreter(g: Graphics2D): ~>[App, Id] = { | |
val g2Interpreter = new GInterpreter(g) | |
new ~>[App, Id] { | |
def apply[A](app: App[A]): Id[A] = { | |
app.run.fold( | |
renderOp => g2Interpreter(renderOp), | |
_.run.fold( | |
interactionOp => DefaultInterpreter(interactionOp), | |
logOp => ConsoleInterpreter(logOp) | |
) | |
) | |
} | |
} | |
} | |
val img = new BufferedImage(250, 250, BufferedImage.TYPE_INT_RGB) | |
drawText("Hello Free!") foldMap interpreter(img.createGraphics()) | |
// 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