Skip to content

Instantly share code, notes, and snippets.

@animatedlew
Created September 12, 2017 05:45
Show Gist options
  • Save animatedlew/dfbdc7d8f8b05ed1c4212ad8ccdec2dc to your computer and use it in GitHub Desktop.
Save animatedlew/dfbdc7d8f8b05ed1c4212ad8ccdec2dc to your computer and use it in GitHub Desktop.
import cats.~>
import cats.free._
import Free._
import Op.interpreter.state
import cats.instances.either._
import language.postfixOps
/** algebraic data type **/
sealed trait ReconOp[A]
case object Delete extends ReconOp[String]
case object Undelete extends ReconOp[String]
case object Suppress extends ReconOp[String]
case object Unsuppress extends ReconOp[String]
case object Active extends ReconOp[String]
/** either with single param **/
type Or[A] = String Either A
object Op {
/** smart constructors **/
def delete: Free[ReconOp, String] = liftF(Delete)
def undelete: Free[ReconOp, String] = liftF(Undelete)
def suppress: Free[ReconOp, String] = liftF(Suppress)
def unsuppress: Free[ReconOp, String] = liftF(Unsuppress)
def active: Free[ReconOp, String] = liftF(Active)
/** test program **/
def testProgram: Free[ReconOp, String] = for {
_ <- active
_ <- suppress
_ <- unsuppress
_ <- delete
r <- undelete
} yield r
/** dummy logic **/
def setActive(s: String): Or[String] = if (s != "deleted") Right("active") else Left("Cannot activate deleted!")
def setDeleted(s: String): Or[String] = if (s == "deleted") Left("Already deleted!") else Right("deleted")
def setUndeleted(s: String): Or[String] = if (state == "deleted") Right("active") else Left("Cannot undelete!")
def setSupressed(s: String): Or[String] = if (state == "active") Right("suppressed") else Left("Only active can be suppressed!")
def setUnsupressed(s: String): Or[String] = if (state == "suppressed") Right("active") else Left("Can only unsuppress active!")
/** interpreter **/
object interpreter extends (ReconOp ~> Or) {
// dummy state -- this could be state monad, stack, and/or enum
var state = "active"
private def setState(s: String): String = { state = s; s}
override def apply[A](fa: ReconOp[A]): Or[A] = {
val result = fa match {
case Active => setActive(state).map(setState)
case Delete => setDeleted(state).map(setState)
case Undelete => setUndeleted(state).map(setState)
case Suppress => setSupressed(state).map(setState)
case Unsuppress => setUnsupressed(state).map(setState)
}
println(s"state: $state")
result.asInstanceOf[Or[A]]
}
}
/** where the magic happens **/
def run: Or[String] = testProgram.foldMap(interpreter)
}
Op.run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment