Advertisement
Guest User

Untitled

a guest
Apr 15th, 2014
45
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 4.04 KB | None | 0 0
  1. package com.rr.sinks
  2. package util
  3.  
  4. import language._
  5.  
  6. import scala.concurrent.duration.Duration
  7.  
  8. import scalaz._
  9. import scalaz.effect._
  10. import scalaz.syntax.monad._
  11.  
  12. // note that F[A] === F[TimeoutT[Identity, A]]
  13. final class TimeoutT[F[_], A] private[util] (private[util] val stack: TimeoutStack[F, A]) {
  14.  
  15.   def run(implicit FL: LiftIO[F], F: Monad[F]): F[A] = stack.run
  16.  
  17.   def flatMap[B](f: A => TimeoutT[F, B])(implicit F: Monad[F]): TimeoutT[F, B] = new TimeoutT(Derived(stack, f))
  18.  
  19.   def map[B](f: A => B)(implicit F: Monad[F]): TimeoutT[F, B] = this flatMap { a => TimeoutT(F point f(a)) }
  20. }
  21.  
  22. object TimeoutT extends TimeoutTInstances {
  23.   def apply[F[_], A](origin: F[A]): TimeoutT[F, A] = new TimeoutT(Resolved(origin))
  24.  
  25.   def setTimeout[F[_]: LiftIO: Functor, A](a: F[A], delay: Duration)(transform: A => TimeoutT[F, A]): F[TimeoutT[F, A]] = now map { init =>
  26.     new TimeoutT(Unresolved(init, a, delay, transform))
  27.   }
  28.  
  29.   def now[F[_]](implicit FL: LiftIO[F]): F[Long] =
  30.     FL liftIO IO { System.currentTimeMillis }
  31. }
  32.  
  33. private sealed trait TimeoutStack[F[_], A] {
  34.   def run(implicit FL: LiftIO[F], F: Monad[F]): F[A]
  35. }
  36.  
  37. private final case class Unresolved[F[_], A](init: Long, seed: F[A], delay: Duration, transform: A => TimeoutT[F, A]) extends TimeoutStack[F, A] {
  38.   def run(implicit FL: LiftIO[F], F: Monad[F]): F[A] = {
  39.     if (delay.isFinite) {
  40.       TimeoutT.now flatMap { now =>
  41.         if (now < init + delay.toMillis) {
  42.           seed
  43.         } else {
  44.           seed flatMap { transform(_).run }
  45.         }
  46.       }
  47.     } else {
  48.       seed
  49.     }
  50.   }
  51. }
  52.  
  53. private final case class Resolved[F[_], A](result: F[A]) extends TimeoutStack[F, A] {
  54.   def run(implicit FL: LiftIO[F], F: Monad[F]): F[A] = result
  55. }
  56.  
  57. private final case class Derived[F[_], A, B](parent: TimeoutStack[F, A], arrow: A => TimeoutT[F, B]) extends TimeoutStack[F, B] {
  58.   def run(implicit FL: LiftIO[F], F: Monad[F]): F[B] =
  59.     parent.run flatMap { arrow(_).run }
  60. }
  61.  
  62. sealed abstract class TimeoutTInstances1 {
  63.   implicit def timeoutTFunctor[F[_], A](implicit F0: Monad[F]): Functor[({ type λ[α] = TimeoutT[F, α] })#λ] = new TimeoutTFunctor[F] {
  64.     def F = F0
  65.   }
  66. }
  67.  
  68. sealed abstract class TimeoutTInstances0 extends TimeoutTInstances1 {
  69.   implicit def timeoutTMonad[F[_], A](implicit F0: Monad[F]): Monad[({ type λ[α] = TimeoutT[F, α] })#λ] = new TimeoutTMonad[F] {
  70.     def F = F0
  71.   }
  72. }
  73.  
  74. sealed abstract class TimeoutTInstances extends TimeoutTInstances0 {
  75.   implicit val timeoutTMonadTrans: Hoist[TimeoutT] = new TimeoutTHoist {}
  76. }
  77.  
  78. private trait TimeoutTFunctor[F[_]] extends Functor[({ type λ[α] = TimeoutT[F, α] })#λ] {
  79.   implicit def F: Monad[F]
  80.  
  81.   override def map[A, B](fa: TimeoutT[F, A])(f: A => B): TimeoutT[F, B] = fa map f
  82. }
  83.  
  84. private trait TimeoutTMonad[F[_]] extends Monad[({ type λ[α] = TimeoutT[F, α] })#λ] {
  85.   implicit def F: Monad[F]
  86.  
  87.   def point[A](a: => A): TimeoutT[F, A] = TimeoutT(F point a)
  88.  
  89.   def bind[A, B](fa: TimeoutT[F, A])(f: A => TimeoutT[F, B]): TimeoutT[F, B] = fa flatMap f
  90. }
  91.  
  92. private trait TimeoutTHoist extends Hoist[TimeoutT] {
  93.   // monad constraint is actually unnecessary here except to preserve signature
  94.   def liftM[G[_]: Monad, A](a: G[A]): TimeoutT[G, A] = TimeoutT(a)
  95.  
  96.   def hoist[M[_]: Monad, N[_]](f: M ~> N) = new (({ type λ[α] = TimeoutT[M, α] })#λ ~> ({ type λ[α] = TimeoutT[N, α] })#λ) {
  97.     def apply[A](timeout: TimeoutT[M, A]): TimeoutT[N, A] = {
  98.       // note: shadowing
  99.       def loop[A](stack: TimeoutStack[M, A]): TimeoutStack[N, A] = stack match {
  100.         case Unresolved(init, seed, delay, transform) =>
  101.           Unresolved(init, f(seed), delay, transform andThen hoist(f).apply)
  102.        
  103.         case Resolved(result) => Resolved(f(result))
  104.        
  105.         case Derived(parent, arrow) => Derived(loop(parent), arrow andThen hoist(f).apply)
  106.       }
  107.      
  108.       new TimeoutT(loop(timeout.stack))
  109.     }
  110.   }
  111.  
  112.   def apply[G[_]](implicit G: Monad[G]): Monad[({ type λ[α] = TimeoutT[G, α] })#λ] = new TimeoutTMonad[G] {
  113.     def F = G
  114.   }
  115. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement