UserMonads and Coproduct Example.
package UserMonads
import UserMonads.MyOp.GetNo
import scalaz.concurrent.Task
import scalaz.~>
/**
* Created by paramin on 2/7/17.
*/
sealed trait MyOp[A] extends Product with Serializable
object MyOp{
final case object GetNo extends MyOp[Int]
}
object MyOpInterpreter extends (MyOp ~> Task) {
override def apply[A](fa: MyOp[A]): Task[A] = fa match {
case GetNo => Task.now(2)
}
}
/**
* Created by paramin on 2/7/17.
*/
package object combiner {
type CombinerApp[A] = Coproduct[UtilOp, MyOp, A]
type CombinerAppF[A] = Free[CombinerApp, A]
}
package UserMonads
import java.sql.Timestamp
import java.util.UUID
import UserMonads.UtilOp.{CurrentTime, GenUUID}
import scalaz.concurrent.Task
import scalaz.~>
/**
* Created by paramin on 2/7/17.
*/
sealed trait UtilOp[A] extends Product with Serializable
object UtilOp {
//Let's group these objects.
final case object GenUUID extends UtilOp[UUID]
final case object CurrentTime extends UtilOp[Timestamp]
}
object UtilOpInterpreter extends (UtilOp ~> Task) {
override def apply[A](fa: UtilOp[A]): Task[A] = fa match {
case GenUUID => Task.now(UUID.randomUUID())
case CurrentTime => Task.now(new Timestamp(System.currentTimeMillis()))
}
}
package UserMonads
import UserMonads.combiner.CombinerApp
import scalaz.concurrent.Task
import scalaz.{-\/, Coproduct, \/-, ~>}
/**
* Created by paramin on 2/7/17.
*/
class CombinedInterp(U : UtilOp ~> Task,
M : MyOp ~> Task) extends (CombinerApp ~> Task){
override def apply[A](fa: CombinerApp[A]): Task[A] = fa match {
case Coproduct(-\/(util)) => U(util)
case Coproduct(\/-(myOp)) => M(myOp)
}
}
//FreeHelpers.scala
package UserMonads
import java.sql.Timestamp
import java.util.UUID
import UserMonads.MyOp.GetNo
import UserMonads.UtilOp.{CurrentTime, GenUUID}
import tortuga.Free
//import tortuga.Free
import scalaz.Inject
/**
* Created by paramin on 2/7/17.
*/
class FreeUtil[F[_]](implicit I: Inject[UtilOp, F]) {
val currentTime: Free[F, Timestamp] = Free.inject[UtilOp, F](CurrentTime)
val genUUID: Free[F, UUID] =
Free.inject[UtilOp, F](GenUUID)
}
object FreeUtil {
implicit def freeUtilInstance[F[_]](implicit T: Inject[UtilOp, F]): FreeUtil[F] = new FreeUtil[F]
}
class FreeMy[F[_]](implicit I: Inject[MyOp, F]) {
val getNo: Free[F, Int] = Free.inject[MyOp, F](GetNo)
}
object FreeMy {
implicit def freeMyInstance[F[_]](implicit T:Inject[MyOp, F]):FreeMy[F] = new FreeMy[F]
}
//Test.scala . YAY!!!
package UserMonads
import UserMonads.combiner.{CombinerApp, CombinerAppF}
import scalaz.stream.time._
import scala.concurrent.duration._
import scalaz.concurrent.{Strategy, Task}
import scalaz.stream.Process
/**
* Created by paramin on 2/7/17.
*/
object Test {
def main(args: Array[String]): Unit = {
println("Iniyan")
val interpreter = new CombinedInterp(UtilOpInterpreter, MyOpInterpreter)
val p = testMethod().foldMap(interpreter)
//We can use awakeEvery here.
implicit val S = Strategy.DefaultStrategy
implicit val scheduler = scalaz.stream.DefaultScheduler
val r = p.flatMap(x => Task.delay(println(x)))
val q = awakeEvery(1.seconds).flatMap(_ => Process.eval(r)) //It will print the same result
//again and again.
//Below one prints different results every time.
// val q = awakeEvery(1.seconds).flatMap(_ => Process.eval((testMethod().foldMap(interpreter)).flatMap(x => Task.delay(println(x)))))
q.run.run
println(p.run)
}
def testMethod()(implicit U:FreeUtil[CombinerApp],
M:FreeMy[CombinerApp]):CombinerAppF[(Long,Long)] = {
import U._
import M._
for{
now <- U.currentTime
k <- M.getNo
}yield((now.getTime, now.getTime * k))
}
}
//Output. will be keep on printing.
Iniyan
(1487114601293,2974229202586)