iniyanp
2/14/2017 - 11:23 PM

UserMonads and Coproduct Example.

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)