Skip to content

Instantly share code, notes, and snippets.

@timperrett
Last active December 11, 2015 21:28
Show Gist options
  • Save timperrett/4662542 to your computer and use it in GitHub Desktop.
Save timperrett/4662542 to your computer and use it in GitHub Desktop.
Example of composing 2.10 futures with scalaz.Validation
package scalaz.akkaz
import scala.language.higherKinds
import scalaz.{Monad, Monoid, Comonad, Traverse, Applicative}
import scala.concurrent.{Await, ExecutionContext, Future, Promise}
import scala.concurrent.duration._
/**
* @see [[scalaz.akkaz.future]] for examples
*/
trait FutureInstances {
implicit def futureMonoid[A](implicit A: Monoid[A], ec: ExecutionContext) = new Monoid[Future[A]] {
override def zero: Future[A] = Future.successful(A.zero)
override def append(f1: Future[A], f2: => Future[A]): Future[A] = (f1 zip f2) map (x => A.append(x._1, x._2))
}
/**Instances without blocking operations*/
trait FutureNonblockingInstances extends Monad[Future] {
protected implicit def executionContext: ExecutionContext
// Functor
override def map[A, B](fa: Future[A])(f: A => B): Future[B] = fa map f
// Monad
override def point[A](a: => A): Future[A] = Future(a)
override def bind[A, B](fa: Future[A])(f: (A) => Future[B]): Future[B] = fa flatMap f
}
/**All instances including those that might use blocking operations*/
trait FutureAllInstances extends Comonad[Future] with Traverse[Future] with FutureNonblockingInstances {
protected def atMost: Duration
// Comonad
override def cojoin[A](a: Future[A]): Future[Future[A]] = Future.successful(a)
override def cobind[A, B](fa: Future[A])(f: (Future[A]) => B): Future[B] = Future.successful(f(fa))
/**Blocks the current Thread until the result is available.*/
override def copoint[A](p: Future[A]): A = Await.result(p, atMost)
// Traverse
/**Blocks the current Thread until the result is available.*/
override def traverseImpl[G[_] : Applicative, A, B](fa: Future[A])(f: (A) => G[B]): G[Future[B]] =
Applicative[G].map(f(Await.result(fa, atMost)))(Future.successful)
/**Blocks the current Thread until the result is available.*/
override def foldRight[A, B](fa: Future[A], z: => B)(f: (A, => B) => B): B =
f(Await.result(fa, atMost), z)
}
/**All Future instances, needs implicit timeout duration in scope for blocking operations*/
implicit def futureInstancesAll(implicit ec: ExecutionContext, d: Duration) = new FutureAllInstances {
override protected implicit val executionContext = ec
override protected val atMost = d
}
/**Future instances without blocking operations.*/
implicit def futureInstancesNonblocking(implicit ec: ExecutionContext) = new FutureNonblockingInstances {
override protected implicit val executionContext = ec
}
}
/**
* Quickstart to import all instances (needs ExecutionContext and optionally timeout in implicit scope):
* {{{
* import scalaz.akkaz.future._
* }}}
*
* To import typeclass instances which don't use blocking operations
* (currently Monad and its dependencies like Functor or Applicative):
* {{{
* val ec: akka.dispatch.ExecutionContext = ...
* implicit val F = scalaz.akkaz.future.futureInstancesNonblocking(ec)
* implicit val M = scalaz.akkaz.future.futureMonoid[A]
* }}}
*
* To import all typeclasses (including Comonad and Traverse):
* {{{
* val ec: akka.dispatch.ExecutionContext = ...
* val atMost: akka.util.Duration = ...
* implicit val F = scalaz.akkaz.future.futureInstancesAll(ec, atMost)
* }}}
*/
object future extends FutureInstances
package futures
import scala.concurrent.{ExecutionContext,Future,future,Promise}
import scalaz._, Scalaz._
object Demo {
// demo purposes only
implicit val ec = ExecutionContext.global
implicit val F = scalaz.akkaz.future.futureInstancesNonblocking(ec)
implicit val M = scalaz.akkaz.future.futureMonoid[String]
type ValidationSNEL[T] = ValidationNEL[String, T]
val app = Applicative[Future].compose[ValidationSNEL]
def handle(a: Int, b: Int): String = (a+b).toString
val r1: Future[ValidationSNEL[Int]] = future { "foo".fail.toValidationNEL }
val r2: Future[ValidationSNEL[Int]] = future { "bar".fail.toValidationNEL }
val output: Future[ValidationSNEL[String]] =
app.apply2(r1,r2)(handle)
def main(args: Array[String]): Unit = {
output.onSuccess {
case r => println(r)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment