Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.rr.sinks
- package util
- import language._
- import scala.concurrent.duration.Duration
- import scalaz._
- import scalaz.effect._
- import scalaz.syntax.monad._
- // note that F[A] === F[TimeoutT[Identity, A]]
- final class TimeoutT[F[_], A] private[util] (private[util] val stack: TimeoutStack[F, A]) {
- def run(implicit FL: LiftIO[F], F: Monad[F]): F[A] = stack.run
- def flatMap[B](f: A => TimeoutT[F, B])(implicit F: Monad[F]): TimeoutT[F, B] = new TimeoutT(Derived(stack, f))
- def map[B](f: A => B)(implicit F: Monad[F]): TimeoutT[F, B] = this flatMap { a => TimeoutT(F point f(a)) }
- }
- object TimeoutT extends TimeoutTInstances {
- def apply[F[_], A](origin: F[A]): TimeoutT[F, A] = new TimeoutT(Resolved(origin))
- def setTimeout[F[_]: LiftIO: Functor, A](a: F[A], delay: Duration)(transform: A => TimeoutT[F, A]): F[TimeoutT[F, A]] = now map { init =>
- new TimeoutT(Unresolved(init, a, delay, transform))
- }
- def now[F[_]](implicit FL: LiftIO[F]): F[Long] =
- FL liftIO IO { System.currentTimeMillis }
- }
- private sealed trait TimeoutStack[F[_], A] {
- def run(implicit FL: LiftIO[F], F: Monad[F]): F[A]
- }
- private final case class Unresolved[F[_], A](init: Long, seed: F[A], delay: Duration, transform: A => TimeoutT[F, A]) extends TimeoutStack[F, A] {
- def run(implicit FL: LiftIO[F], F: Monad[F]): F[A] = {
- if (delay.isFinite) {
- TimeoutT.now flatMap { now =>
- if (now < init + delay.toMillis) {
- seed
- } else {
- seed flatMap { transform(_).run }
- }
- }
- } else {
- seed
- }
- }
- }
- private final case class Resolved[F[_], A](result: F[A]) extends TimeoutStack[F, A] {
- def run(implicit FL: LiftIO[F], F: Monad[F]): F[A] = result
- }
- private final case class Derived[F[_], A, B](parent: TimeoutStack[F, A], arrow: A => TimeoutT[F, B]) extends TimeoutStack[F, B] {
- def run(implicit FL: LiftIO[F], F: Monad[F]): F[B] =
- parent.run flatMap { arrow(_).run }
- }
- sealed abstract class TimeoutTInstances1 {
- implicit def timeoutTFunctor[F[_], A](implicit F0: Monad[F]): Functor[({ type λ[α] = TimeoutT[F, α] })#λ] = new TimeoutTFunctor[F] {
- def F = F0
- }
- }
- sealed abstract class TimeoutTInstances0 extends TimeoutTInstances1 {
- implicit def timeoutTMonad[F[_], A](implicit F0: Monad[F]): Monad[({ type λ[α] = TimeoutT[F, α] })#λ] = new TimeoutTMonad[F] {
- def F = F0
- }
- }
- sealed abstract class TimeoutTInstances extends TimeoutTInstances0 {
- implicit val timeoutTMonadTrans: Hoist[TimeoutT] = new TimeoutTHoist {}
- }
- private trait TimeoutTFunctor[F[_]] extends Functor[({ type λ[α] = TimeoutT[F, α] })#λ] {
- implicit def F: Monad[F]
- override def map[A, B](fa: TimeoutT[F, A])(f: A => B): TimeoutT[F, B] = fa map f
- }
- private trait TimeoutTMonad[F[_]] extends Monad[({ type λ[α] = TimeoutT[F, α] })#λ] {
- implicit def F: Monad[F]
- def point[A](a: => A): TimeoutT[F, A] = TimeoutT(F point a)
- def bind[A, B](fa: TimeoutT[F, A])(f: A => TimeoutT[F, B]): TimeoutT[F, B] = fa flatMap f
- }
- private trait TimeoutTHoist extends Hoist[TimeoutT] {
- // monad constraint is actually unnecessary here except to preserve signature
- def liftM[G[_]: Monad, A](a: G[A]): TimeoutT[G, A] = TimeoutT(a)
- def hoist[M[_]: Monad, N[_]](f: M ~> N) = new (({ type λ[α] = TimeoutT[M, α] })#λ ~> ({ type λ[α] = TimeoutT[N, α] })#λ) {
- def apply[A](timeout: TimeoutT[M, A]): TimeoutT[N, A] = {
- // note: shadowing
- def loop[A](stack: TimeoutStack[M, A]): TimeoutStack[N, A] = stack match {
- case Unresolved(init, seed, delay, transform) =>
- Unresolved(init, f(seed), delay, transform andThen hoist(f).apply)
- case Resolved(result) => Resolved(f(result))
- case Derived(parent, arrow) => Derived(loop(parent), arrow andThen hoist(f).apply)
- }
- new TimeoutT(loop(timeout.stack))
- }
- }
- def apply[G[_]](implicit G: Monad[G]): Monad[({ type λ[α] = TimeoutT[G, α] })#λ] = new TimeoutTMonad[G] {
- def F = G
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement