Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add collections and parallel syntax #723

Merged
merged 9 commits into from
Jul 23, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tofu.syntax
import cats.syntax._
import cats.{Applicative, Apply, FlatMap, Functor, Monad, Semigroupal}
import cats.Defer

object monadic extends TupleSemigroupalSyntax with ApplicativeSyntax with MonadSyntax {
def unit[F[_]](implicit F: Applicative[F]): F[Unit] = F.unit
Expand Down Expand Up @@ -51,6 +52,10 @@ object monadic extends TupleSemigroupalSyntax with ApplicativeSyntax with MonadS
def map2[B, Z](fb: F[B])(f: (C, B) => Z)(implicit F: Apply[F]): F[Z] = F.map2(fa, fb)(f)
def map2Eval[B, Z](fb: cats.Eval[F[B]])(f: (C, B) => Z)(implicit F: Apply[F]): cats.Eval[F[Z]] =
F.map2Eval(fa, fb)(f)

def replicate_(count: Long)(implicit F: Applicative[F], FD: Defer[F]): F[Unit] =
if (count <= 0) unit[F]
else productR(FD.defer(replicate_(count - 1)))
FunFunFine marked this conversation as resolved.
Show resolved Hide resolved
}

implicit final class TofuFlatMapOps[F[_], C](private val fa: F[C]) extends AnyVal {
Expand Down
86 changes: 86 additions & 0 deletions modules/kernel/src/main/scala/tofu/syntax/collections.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package tofu.syntax

import cats.syntax._
import cats.{Applicative, Traverse, TraverseFilter}
import cats.syntax.functor._
import cats.data.State
import cats.data.StateT
import cats.Monad
import cats.free.Free
import cats.FlatMap
object collections
FunFunFine marked this conversation as resolved.
Show resolved Hide resolved
extends FoldableSyntax with TraverseSyntax with TraverseFilterSyntax with FunctorFilterSyntax
with TofuTraverseSyntax {

final implicit class TofuCollectionsSyntax[F[_], A](private val fa: F[A]) extends AnyVal {

/** a combination of map and scanLeft
* it applies a function to each element of a structure,
* passing an accumulating parameter from left to right,
* and returning a final value of this accumulator together with the new structure.
*/
def mapAccumL[B, C](fa: F[A], start: B)(step: (B, A) => (B, C))(implicit F: Traverse[F]): (B, F[C]) =
F.traverse(fa)(a => State((b: B) => step(b, a))).run(start).value

/** like mapAccumL, but drop the final state
*/
def mapAccumL_[B, C](fa: F[A], start: B)(step: (B, A) => (B, C))(implicit F: Traverse[F]): F[C] =
mapAccumL(fa, start)(step)._2

/** like [[mapAccumL]] but also combines monadic effects of `G`
* stack-safety relies on a stack safety of G
*/
def mapAccumM[G[_]: Monad, B, C](fa: F[A], start: B)(step: (B, A) => G[(B, C)])(implicit
F: Traverse[F]
): G[(B, F[C])] =
F.traverse(fa)(a => StateT((b: B) => step(b, a))).run(start)

/** like [[mapAccumM]] but drop the final state
*/
def mapAccumM_[G[_]: Monad, B, C](fa: F[A], start: B)(step: (B, A) => G[(B, C)])(implicit
F: Traverse[F]
): G[F[C]] = mapAccumM(fa, start)(step).map(_._2)

/** like [[mapAccumL]] but also combines monadic effects of `G`
* stack-safety guaranteed via Free
*/
def mapAccumF[G[_]: Monad, B, C](fa: F[A], start: B)(step: (B, A) => G[(B, C)])(implicit
F: Traverse[F]
): G[(B, F[C])] =
F.traverse(fa)(a => StateT((b: B) => Free.liftF(step(b, a)))).run(start).runTailRec

/** like [[mapAccumF]] but drop the final state
*/
def mapAccumF_[G[_]: Monad, B, C](fa: F[A], start: B)(step: (B, A) => G[(B, C)])(implicit
F: Traverse[F]
): G[F[C]] = mapAccumF(fa, start)(step).map(_._2)
}

final implicit class TofuSequenceOps[G[_], T[_], A](private val fta: T[G[A]]) extends AnyVal {
def sequence(implicit G: Applicative[G], T: Traverse[T]): G[T[A]] =
T.sequence[G, A](fta)
}

final implicit class TofuFlatSequenceOps[G[_], T[_], A](private val fta: T[G[T[A]]]) extends AnyVal {
def flatSequence(implicit
G: Applicative[G],
T: Traverse[T],
TF: FlatMap[T],
): G[T[A]] = T.flatSequence[G, A](fta)
}
}

@deprecated("use tofu.syntax.collections", since = "0.11.0")
object traverse extends TofuTraverseSyntax

trait TofuTraverseSyntax {
final implicit def tofuTraverseSyntax[F[_], A](ta: F[A]): TraverseOps[F, A] = new TraverseOps[F, A](ta)
}

final class TraverseOps[F[_], A](private val ta: F[A]) extends AnyVal {
def traverseKey[G[_]: Applicative, B](f: A => G[B])(implicit T: Traverse[F]): G[F[(A, B)]] =
T.traverse(ta)(a => f(a).map((a, _)))

def traverseKeyFilter[G[_]: Applicative, B](f: A => G[Option[B]])(implicit TF: TraverseFilter[F]): G[F[(A, B)]] =
TF.traverseFilter(ta)(a => f(a).map(_.map((a, _))))
}
23 changes: 23 additions & 0 deletions modules/kernel/src/main/scala/tofu/syntax/parallel.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package tofu.syntax
import cats.syntax._
import cats.Parallel
import cats.Defer

object parallel
extends ParallelSyntax with ParallelTraverseSyntax with ParallelFlatSyntax with ParallelApplySyntax
with ParallelBitraverseSyntax with ParallelUnorderedTraverseSyntax with ParallelFoldMapASyntax
with ParallelTraverseFilterSyntax {

final implicit class TofuParallelOps[F[_], A](private val fa: F[A]) extends AnyVal {
def parReplicate(count: Int)(implicit F: Parallel[F]): F[List[A]] =
F.sequential(F.applicative.replicateA(count, F.parallel(fa)))

def parReplicate_(count: Long)(implicit F: Parallel[F], FD: Defer[F]): F[Unit] =
if (count <= 0) F.monad.unit
else
F.sequential(F.applicative.productR(F.parallel(fa))(F.parallel(FD.defer(parReplicate_(count - 1)))))

def parReplicateBatch_(count: Long, batch: Long)(implicit F: Parallel[F], FD: Defer[F]): F[Unit] =
F.monad.productR(parReplicate_(count.min(batch)))(FD.defer(parReplicateBatch_(count - batch, batch)))
}
}
14 changes: 0 additions & 14 deletions modules/kernel/src/main/scala/tofu/syntax/traverse.scala

This file was deleted.