From 82b6ae7ab52df111b27c34c81f1f61bd3837a750 Mon Sep 17 00:00:00 2001 From: Luka Jacobowitz Date: Mon, 21 Aug 2017 19:36:08 +0200 Subject: [PATCH] Initial version of Parallel --- core/src/main/scala/cats/Parallel.scala | 60 +++++++++++++++++++ .../src/main/scala/cats/syntax/parallel.scala | 32 ++++++++++ 2 files changed, 92 insertions(+) create mode 100644 core/src/main/scala/cats/Parallel.scala create mode 100644 core/src/main/scala/cats/syntax/parallel.scala diff --git a/core/src/main/scala/cats/Parallel.scala b/core/src/main/scala/cats/Parallel.scala new file mode 100644 index 00000000000..da80bacaeb4 --- /dev/null +++ b/core/src/main/scala/cats/Parallel.scala @@ -0,0 +1,60 @@ +package cats + +trait Parallel[M[_], F[_]] { + def applicative: Applicative[F] + def sequential(implicit M: Monad[M]): F ~> M + def parallel(implicit M: Monad[M]): M ~> F +} + +object Parallel { + def parSequence[T[_]: Traverse, M[_]: Monad, F[_], A] + (tma: T[M[A]])(implicit P: Parallel[M, F]): M[T[A]] = { + implicit val F = P.applicative + val fta: F[T[A]] = Traverse[T].traverse(tma)(P.parallel.apply) + P.sequential.apply(fta) + } + + def parTraverse[T[_]: Traverse, M[_]: Monad, F[_], A, B] + (ta: T[A])(f: A => M[B])(implicit P: Parallel[M, F]): M[T[B]] = { + implicit val F = P.applicative + val gtb: F[T[B]] = Traverse[T].traverse(ta)(f andThen P.parallel.apply) + P.sequential.apply(gtb) + } + + def parSequence_[T[_]: Foldable, M[_]: Monad, F[_], A] + (tma: T[M[A]])(implicit P: Parallel[M, F]): M[Unit] = { + implicit val F = P.applicative + val fu: F[Unit] = Foldable[T].traverse_(tma)(P.parallel.apply) + P.sequential.apply(fu) + } + + def parTraverse_[T[_]: Foldable, M[_]: Monad, F[_], A, B] + (ta: T[A])(f: A => M[B])(implicit P: Parallel[M, F]): M[Unit] = { + implicit val F = P.applicative + val gtb: F[Unit] = Foldable[T].traverse_(ta)(f andThen P.parallel.apply) + P.sequential.apply(gtb) + } + + def parAp[M[_]: Monad, F[_], A, B](mf: M[A => B]) + (ma: M[A]) + (implicit P: Parallel[M, F]): M[B] = { + implicit val F = P.applicative + val fb = Applicative[F].ap(P.parallel.apply(mf))(P.parallel.apply(ma)) + P.sequential.apply(fb) + } + + def parProduct[M[_]: Monad, F[_], A, B](ma: M[A], mb: M[B]) + (implicit P: Parallel[M, F]): M[(A, B)] = + parAp(Monad[M].map(ma)(a => (b: B) => (a, b)))(mb) + + def parAp2[M[_]: Monad, F[_], A, B, Z](ff: M[(A, B) => Z]) + (ma: M[A], mb: M[B]) + (implicit P: Parallel[M, F]): M[Z] = + Monad[M].map(parProduct(ma, parProduct(mb, ff))) { case (a, (b, f)) => f(a, b) } + + def parMap2[M[_]: Monad, F[_], A, B, C](ma: M[A], mb: M[B]) + (f: (A, B) => C) + (implicit P: Parallel[M, F]): M[C] = { + Monad[M].map(parProduct(ma, mb)) { case (a, b) => f(a, b) } + } +} diff --git a/core/src/main/scala/cats/syntax/parallel.scala b/core/src/main/scala/cats/syntax/parallel.scala new file mode 100644 index 00000000000..470e56b0d28 --- /dev/null +++ b/core/src/main/scala/cats/syntax/parallel.scala @@ -0,0 +1,32 @@ +package cats.syntax + +import cats.{Monad, Parallel, Traverse} + +trait parallel { + implicit final def catsSyntaxParallelTraverse[T[_]: Traverse, A] + (ta: T[A]): ParallelTraversableOps[T, A] = new ParallelTraversableOps[T, A] { + override def self = ta + + override val typeClassInstance: Traverse[T] = T + } +} + + + + +trait ParallelTraversableOps[T[_], A] { + + val typeClassInstance : cats.Traverse[T] + def self : T[A] + + implicit val T = typeClassInstance + + def parTraverse[M[_]: Monad, F[_], B] + (f: A => M[B])(implicit P: Parallel[M, F]): M[T[B]] = + Parallel.parTraverse(self)(f) + + def parSequence[M[_]: Monad, F[_], B](implicit ev: A <:< M[B], P: Parallel[M, F]): M[T[B]] = + Parallel.parSequence(self.asInstanceOf[T[M[B]]]) + + +}