Last active
December 11, 2015 21:28
-
-
Save timperrett/4662542 to your computer and use it in GitHub Desktop.
Example of composing 2.10 futures with scalaz.Validation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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