-
-
Save tbrown1979/74a545c5328a51578935 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 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