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 FunctionN.liftN, parLiftN #4340

Merged
merged 11 commits into from
Sep 29, 2024
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/syntax/apply.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
package cats
package syntax

trait ApplySyntax extends TupleSemigroupalSyntax {
trait ApplySyntax extends TupleSemigroupalSyntax with FunctionApplySyntax {
implicit final def catsSyntaxApply[F[_], A](fa: F[A])(implicit F: Apply[F]): Apply.Ops[F, A] =
new Apply.Ops[F, A] {
type TypeClassType = Apply[F]
Expand Down
44 changes: 41 additions & 3 deletions project/Boilerplate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ object Boilerplate {
GenParallelArityFunctions,
GenParallelArityFunctions2,
GenFoldableArityFunctions,
GenFunctionSyntax,
GenTupleParallelSyntax,
GenTupleShowInstances,
GenTupleMonadInstances,
Expand Down Expand Up @@ -594,7 +595,7 @@ object Boilerplate {
| * @groupname FoldableSlidingN foldable arity
| * @groupdesc FoldableSlidingN
| * Group sequential elements into fixed sized tuples by passing a "sliding window" over them.
| *
| *
| * A foldable with fewer elements than the window size will return an empty list unlike `Iterable#sliding(size: Int)`.
| * Example:
| * {{{
Expand All @@ -604,12 +605,12 @@ object Boilerplate {
| *
| * scala> Foldable[List].sliding4((1 to 10).toList)
| * val res1: List[(Int, Int, Int, Int)] = List((1,2,3,4), (2,3,4,5), (3,4,5,6), (4,5,6,7), (5,6,7,8), (6,7,8,9), (7,8,9,10))
| *
| *
| * scala> Foldable[List].sliding4((1 to 2).toList)
| * val res2: List[(Int, Int, Int, Int)] = List()
| *
| * }}}
| *
| *
| * @groupprio FoldableSlidingN 999
| *
| */
Expand All @@ -621,4 +622,41 @@ object Boilerplate {
"""
}
}

object GenFunctionSyntax extends Template {
def filename(root: File) = root / "cats" / "syntax" / "FunctionApplySyntax.scala"

override def range = 2 to maxArity

def content(tv: TemplateVals) = {
import tv._

val function = s"Function$arity[${`A..N`}, T]"

val typedParams = synVals.zip(synTypes).map { case (v, t) => s"$v: F[$t]" }.mkString(", ")

block"""
|package cats
|package syntax
|
|import cats.Functor
|import cats.Semigroupal
|
|trait FunctionApplySyntax {
| implicit def catsSyntaxFunction1Apply[T, A0](f: Function1[A0, T]): Function1ApplyOps[T, A0] = new Function1ApplyOps(f)
- implicit def catsSyntaxFunction${arity}Apply[T, ${`A..N`}](f: $function): Function${arity}ApplyOps[T, ${`A..N`}] = new Function${arity}ApplyOps(f)
|}
|
|private[syntax] final class Function1ApplyOps[T, A0](private val f: Function1[A0, T]) extends Serializable {
| def applyN[F[_]: Functor](a0: F[A0]): F[T] = Functor[F].map(a0)(f)
| def tupledF[F[_]: Functor](t: F[A0]): F[T] = Functor[F].map(t)(f)
|}
|
-private[syntax] final class Function${arity}ApplyOps[T, ${`A..N`}](private val f: $function) extends Serializable {
- def applyN[F[_]: Functor: Semigroupal]($typedParams): F[T] = Semigroupal.map$arity(${`a..n`})(f)
- def tupledF[F[_]: Functor](t: F[${`(A..N)`}]): F[T] = Functor[F].map(t)(f.tupled)
-}
"""
}
}
}
22 changes: 22 additions & 0 deletions tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,28 @@ object SyntaxSuite {
tfa.parFlatMap(mfone)
}

def testApplyN[F[_]: Apply, A, B, C, T] = {
val fa = mock[F[A]]
val fb = mock[F[B]]
val fc = mock[F[C]]

val fapply2 = mock[(A, B) => T]

val result2 = fapply2.applyN(fa, fb)

result2: F[T]
kubukoz marked this conversation as resolved.
Show resolved Hide resolved

val fapply3 = mock[(A, B, C) => T]

val result3 = fapply3.applyN(fa, fb, fc)

result3: F[T]

val result3Tupled = fapply3.tupledF((fa, fb, fc).tupled)

result3Tupled: F[T]
}

def testParallelBi[M[_], F[_], T[_, _]: Bitraverse, A, B, C, D](implicit P: Parallel.Aux[M, F]): Unit = {
val tab = mock[T[A, B]]
val f = mock[A => M[C]]
Expand Down