Last active
October 26, 2016 18:42
-
-
Save andyscott/8831c5590685b958100d65a5b22c2ac4 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 monix.eval.Task | |
import monix.execution.Scheduler | |
import scala.concurrent.Await | |
import scala.concurrent.duration._ | |
object FizzBuzzer { | |
def main(args: Array[String]): Unit = { | |
val taskIO: IOOp ~> Task = | |
new (IOOp ~> Task) { | |
import IOOp._ | |
override def apply[A](op: IOOp[A]): Task[A] = op match { | |
case PrintFizz ⇒ Task(println("Fizz")) | |
case PrintBuzz ⇒ Task(println("Buzz")) | |
case PrintFizzBuzz ⇒ Task(println("FizzBuzz")) | |
case PrintNum(n) ⇒ Task(println(s"$n")) | |
} | |
} | |
val io = new IOOps(taskIO) | |
val math = new MathOps(new DefaultMathOpInterpreter) | |
def fizzBuzz(current: Long, zero: Long, three: Long, five: Long, hundo: Long): Task[Unit] = | |
for { | |
mod3isZero ← math.mod(current, three).map(_ == zero) | |
mod5isZero ← math.mod(current, five).map(_ == zero) | |
_ ← (mod3isZero, mod5isZero) match { | |
case (true, true) ⇒ io.printFizzBuzz() | |
case (true, false) ⇒ io.printFizz() | |
case (false, true) ⇒ io.printBuzz() | |
case _ ⇒ io.printNum(current) | |
} | |
next ← math.increment(current) | |
continue ← math.gt(next, hundo).map(!_) | |
_ ← { | |
if (continue) fizzBuzz(next, zero, three, five, hundo) | |
else Task(()) | |
} | |
} yield () | |
val program = for { | |
`0` ← math.zero() | |
`1` ← math.increment(`0`) | |
`2` ← math.increment(`1`) | |
`3` ← math.increment(`2`) | |
`4` ← math.increment(`3`) | |
`5` ← math.increment(`4`) | |
`10` ← math.times(`2`, `5`) | |
`100` ← math.times(`10`, `10`) | |
_ ← fizzBuzz(`1`, `0`, `3`, `5`, `100`) | |
} yield () | |
val future = program.runAsync(Scheduler.global) | |
Await.result(future, 10.seconds) | |
} | |
} | |
class IOOps[F[_]](lift: IOOp ~> F) { | |
import IOOp._ | |
def printFizz(): F[Unit] = lift(PrintFizz) | |
def printBuzz(): F[Unit] = lift(PrintBuzz) | |
def printFizzBuzz(): F[Unit] = lift(PrintFizzBuzz) | |
def printNum[N: Numeric](n: N): F[Unit] = lift(PrintNum(n)) | |
} | |
sealed trait IOOp[A] | |
object IOOp { | |
case object PrintFizz extends IOOp[Unit] | |
case object PrintBuzz extends IOOp[Unit] | |
case object PrintFizzBuzz extends IOOp[Unit] | |
case class PrintNum[N: Numeric](n: N) extends IOOp[Unit] | |
} | |
class MathOps[F[_]](lift: MathOp ~> F) { | |
import MathOp._ | |
def zero(): F[Long] = lift(Zero()) | |
def increment(v: Long): F[Long] = lift(Increment(v)) | |
def mod(dividend: Long, divisor: Long): F[Long] = lift(Mod(dividend, divisor)) | |
def times(x: Long, y: Long): F[Long] = lift(Times(x, y)) | |
def gt(x: Long, y: Long): F[Boolean] = lift(Gt(x, y)) | |
} | |
sealed trait MathOp[A] | |
object MathOp { | |
case class Zero() extends MathOp[Long] | |
case class Increment(v: Long) extends MathOp[Long] | |
case class Mod(dividend: Long, divisor: Long) extends MathOp[Long] | |
case class Times(x: Long, y: Long) extends MathOp[Long] | |
case class Gt(x: Long, y: Long) extends MathOp[Boolean] | |
} | |
class DefaultMathOpInterpreter extends (MathOp ~> Task) { | |
import MathOp._ | |
override def apply[A](rawOp: MathOp[A]): Task[A] = rawOp match { | |
case op: Zero ⇒ handleZero(op) | |
case op: Increment ⇒ handleIncrement(op) | |
case op: Mod ⇒ handleMod(op) | |
case op: Times ⇒ handleTimes(op) | |
case op: Gt ⇒ handleGt(op) | |
} | |
def handleZero(op: Zero): Task[Long] = | |
Task(0L) | |
def handleIncrement(op: Increment): Task[Long] = | |
Task(op.v + 1L) | |
def handleMod(op: Mod): Task[Long] = Task { | |
op.dividend % op.divisor | |
} | |
def handleTimes(op: Times): Task[Long] = Task { | |
op.x * op.y | |
} | |
def handleGt(op: Gt): Task[Boolean] = | |
Task(op.x > op.y) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment