Created
September 12, 2017 05:45
-
-
Save animatedlew/dfbdc7d8f8b05ed1c4212ad8ccdec2dc 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
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