Skip to content

Commit

Permalink
Apply syntax for tuples, fixes #1363
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidGregory084 committed May 20, 2017
1 parent a5348cf commit eefd70b
Show file tree
Hide file tree
Showing 11 changed files with 45 additions and 69 deletions.
3 changes: 0 additions & 3 deletions .jvmopts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
# see https://weblogs.java.net/blog/kcpeppe/archive/2013/12/11/case-study-jvm-hotspot-flags
-Dfile.encoding=UTF8
-Xms1G
-Xmx6G
-XX:MaxPermSize=512M
-XX:ReservedCodeCacheSize=250M
-XX:+TieredCompilation
-XX:-UseGCOverheadLimit
# effectively adds GC to Perm space
-XX:+CMSClassUnloadingEnabled
# must be enabled for CMSClassUnloadingEnabled to work
-XX:+UseConcMarkSweepGC
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/data/EitherT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) {
* scala> val v1: Validated[NonEmptyList[Error], Int] = Validated.Invalid(NonEmptyList.of("error 1"))
* scala> val v2: Validated[NonEmptyList[Error], Int] = Validated.Invalid(NonEmptyList.of("error 2"))
* scala> val eithert: EitherT[Option, Error, Int] = EitherT(Some(Either.left("error 3")))
* scala> eithert.withValidated { v3 => (v1 |@| v2 |@| v3.leftMap(NonEmptyList.of(_))).map{ case (i, j, k) => i + j + k } }
* scala> eithert.withValidated { v3 => (v1, v2, v3.leftMap(NonEmptyList.of(_))).mapN { case (i, j, k) => i + j + k } }
* res0: EitherT[Option, NonEmptyList[Error], Int] = EitherT(Some(Left(NonEmptyList(error 1, error 2, error 3))))
* }}}
*/
Expand Down
1 change: 0 additions & 1 deletion core/src/main/scala/cats/syntax/all.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ trait AllSyntax
with StrongSyntax
with TraverseFilterSyntax
with TraverseSyntax
with TupleSyntax
with ValidatedSyntax
with VectorSyntax
with WriterSyntax
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/syntax/apply.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cats
package syntax

trait ApplySyntax {
trait ApplySyntax extends TupleCartesianSyntax {
implicit final def catsSyntaxApply[F[_], A](fa: F[A])(implicit F: Apply[F]): Apply.Ops[F, A] =
new Apply.Ops[F, A] {
val self = fa
Expand Down
1 change: 0 additions & 1 deletion core/src/main/scala/cats/syntax/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ package object syntax {
object monadTrans extends MonadTransSyntax
object traverse extends TraverseSyntax
object traverseFilter extends TraverseFilterSyntax
object tuple extends TupleSyntax
object validated extends ValidatedSyntax
object vector extends VectorSyntax
object writer extends WriterSyntax
Expand Down
4 changes: 0 additions & 4 deletions core/src/main/scala/cats/syntax/tuple.scala

This file was deleted.

2 changes: 1 addition & 1 deletion docs/src/main/tut/typeclasses/applicative.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ The second expects the effects in a tuple and works by enriching syntax on top o
`TupleN` types.

```tut:book
(o1, o2).map2((i: Int, s: String) => i.toString ++ s)
(o1, o2).mapN((i: Int, s: String) => i.toString ++ s)
```

## Further Reading
Expand Down
2 changes: 1 addition & 1 deletion free/src/test/scala/cats/free/FreeApplicativeTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class FreeApplicativeTests extends CatsSuite {
// fixed by #568
val fli1 = FreeApplicative.lift[List, Int](List(1, 3, 5, 7))
val fli2 = FreeApplicative.lift[List, Int](List(1, 3, 5, 7))
(fli1 |@| fli2).map(_ + _)
(fli1, fli2).mapN(_ + _)
}

test("FreeApplicative#analyze") {
Expand Down
18 changes: 13 additions & 5 deletions project/Boilerplate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -238,15 +238,21 @@ object Boilerplate {

val map =
if (arity == 1) s"def map[Z](f: (${`A..N`}) => Z)(implicit functor: Functor[F]): F[Z] = functor.map($tupleArgs)(f)"
else s"def map$arity[Z](f: (${`A..N`}) => Z)(implicit functor: Functor[F], cartesian: Cartesian[F]): F[Z] = Cartesian.map$arity($tupleArgs)(f)"
else s"def mapN[Z](f: (${`A..N`}) => Z)(implicit functor: Functor[F]): F[Z] = Cartesian.map$arity($tupleArgs)(f)"

val contramap =
if (arity == 1) s"def contramap[Z](f: Z => (${`A..N`}))(implicit contravariant: Contravariant[F]): F[Z] = contravariant.contramap($tupleArgs)(f)"
else s"def contramap$arity[Z](f: Z => (${`A..N`}))(implicit contravariant: Contravariant[F], cartesian: Cartesian[F]): F[Z] = Cartesian.contramap$arity($tupleArgs)(f)"
else s"def contramapN[Z](f: Z => (${`A..N`}))(implicit contravariant: Contravariant[F]): F[Z] = Cartesian.contramap$arity($tupleArgs)(f)"

val imap =
if (arity == 1) s"def imap[Z](f: (${`A..N`}) => Z)(g: Z => (${`A..N`}))(implicit invariant: Invariant[F]): F[Z] = invariant.imap($tupleArgs)(f)(g)"
else s"def imap$arity[Z](f: (${`A..N`}) => Z)(g: Z => (${`A..N`}))(implicit invariant: Invariant[F], cartesian: Cartesian[F]): F[Z] = Cartesian.imap$arity($tupleArgs)(f)(g)"
else s"def imapN[Z](f: (${`A..N`}) => Z)(g: Z => (${`A..N`}))(implicit invariant: Invariant[F]): F[Z] = Cartesian.imap$arity($tupleArgs)(f)(g)"

val tupled = if (arity != 1) {
s"def tupled(implicit invariant: Invariant[F]): F[(${`A..N`})] = Cartesian.tuple$n($tupleArgs)"
} else {
""
}

block"""
|package cats
Expand All @@ -255,13 +261,15 @@ object Boilerplate {
|import cats.functor.{Contravariant, Invariant}
|
|trait TupleCartesianSyntax {
- implicit def catsSyntaxTuple${arity}Cartesian[F[_], ${`A..N`}]($tupleTpe): Tuple${arity}CartesianOps[F, ${`A..N`}] = new Tuple${arity}CartesianOps(t$arity)
- implicit def catsSyntaxTuple${arity}Cartesian[F[_], ${`A..N`}]($tupleTpe)(implicit C: Cartesian[F]): Tuple${arity}CartesianOps[F, ${`A..N`}] = new Tuple${arity}CartesianOps(t$arity, C)
|}
|
-private[syntax] final class Tuple${arity}CartesianOps[F[_], ${`A..N`}]($tupleTpe) {
-private[syntax] final class Tuple${arity}CartesianOps[F[_], ${`A..N`}]($tupleTpe, C: Cartesian[F]) {
- implicit val cartesian: Cartesian[F] = C
- $map
- $contramap
- $imap
- $tupled
- def apWith[Z](f: F[(${`A..N`}) => Z])(implicit apply: Apply[F]): F[Z] = apply.ap$n(f)($tupleArgs)
-}
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package tests
import cats.laws.discipline.eq.catsLawsEqForFn1
import cats.laws.discipline.{InvariantMonoidalTests, SerializableTests}
import cats.instances.all._
import cats.syntax.cartesian._
import cats.syntax.apply._
import cats.Eq
import org.scalacheck.{Arbitrary, Gen}

Expand Down Expand Up @@ -42,7 +42,7 @@ object CsvCodecInvariantMonoidalTests {
def read(s: CSV): (Option[(A, B)], CSV) = {
val (a1, s1) = fa.read(s)
val (a2, s2) = fb.read(s1)
((a1 |@| a2).map(_ -> _), s2)
((a1, a2).mapN(_ -> _), s2)
}

def write(a: (A, B)): CSV =
Expand Down
75 changes: 26 additions & 49 deletions tests/src/test/scala/cats/tests/SyntaxTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -180,28 +180,37 @@ object SyntaxTests extends AllInstances with AllSyntax {
val fb1: F[B] = fa.as(b)
}

def testApply[F[_]: Apply, A, B, C, D, Z]: Unit = {
def testApply[F[_]: Apply : Cartesian, G[_]: Contravariant : Cartesian, H[_]: Invariant : Cartesian, A, B, C, D, E, Z] = {
val tfabc = mock[(F[A], F[B], F[C])]
val fa = mock[F[A]]
val fab = mock[F[A => B]]
val fb0: F[B] = fab.ap(fa)

val fb = mock[F[B]]
val fabz = mock[F[(A, B) => Z]]
val fz0: F[Z] = fabz.ap2(fa, fb)
val fc = mock[F[C]]
val f = mock[(A, B, C) => Z]
val ff = mock[F[(A, B, C) => Z]]

tfabc mapN f
(fa, fb, fc) mapN f
(fa, fb, fc) apWith ff

val f = mock[(A, B) => Z]
val fz1: F[Z] = fa.map2(fb)(f)
val tgabc = mock[(G[A], G[B])]
val ga = mock[G[A]]
val gb = mock[G[B]]
val g = mock[Z => (A, B)]

val f1 = mock[(A, B) => Z]
val ff1 = mock[F[(A, B) => Z]]
val fz2: F[Z] = (fa |@| fb).map(f1)
val fz3: F[Z] = (fa |@| fb).apWith(ff1)
tgabc contramapN g
(ga, gb) contramapN g

val fc = mock[F[C]]
val f2 = mock[(A, B, C) => Z]
val ff2 = mock[F[(A, B, C) => Z]]
val fz4: F[Z] = (fa |@| fb |@| fc).map(f2)
val fz5: F[Z] = (fa |@| fb |@| fc).apWith(ff2)
val thabcde = mock[(H[A], H[B], H[C], H[D], H[E])]
val ha = mock[H[A]]
val hb = mock[H[B]]
val hc = mock[H[C]]
val hd = mock[H[D]]
val he = mock[H[E]]
val f5 = mock[(A, B, C, D, E) => Z]
val g5 = mock[Z => (A, B, C, D, E)]

thabcde.imapN(f5)(g5)
(ha, hb, hc, hd, he).imapN(f5)(g5)
}

def testBifoldable[F[_, _]: Bifoldable, A, B, C, D: Monoid]: Unit = {
Expand Down Expand Up @@ -274,38 +283,6 @@ object SyntaxTests extends AllInstances with AllSyntax {
val gea4 = ga.recoverWith(pfegea)
}

def testTupleArity[F[_]: Apply : Cartesian, G[_]: Contravariant : Cartesian, H[_]: Invariant : Cartesian, A, B, C, D, E, Z] = {
val tfabc = mock[(F[A], F[B], F[C])]
val fa = mock[F[A]]
val fb = mock[F[B]]
val fc = mock[F[C]]
val f = mock[(A, B, C) => Z]
val ff = mock[F[(A, B, C) => Z]]

tfabc map3 f
(fa, fb, fc) map3 f
(fa, fb, fc) apWith ff

val tgabc = mock[(G[A], G[B])]
val ga = mock[G[A]]
val gb = mock[G[B]]
val g = mock[Z => (A, B)]

tgabc contramap2 g
(ga, gb) contramap2 g

val thabcde = mock[(H[A], H[B], H[C], H[D], H[E])]
val ha = mock[H[A]]
val hb = mock[H[B]]
val hc = mock[H[C]]
val hd = mock[H[D]]
val he = mock[H[E]]
val f5 = mock[(A, B, C, D, E) => Z]
val g5 = mock[Z => (A, B, C, D, E)]

thabcde.imap5(f5)(g5)
(ha, hb, hc, hd, he).imap5(f5)(g5)
}
}

/**
Expand Down

0 comments on commit eefd70b

Please sign in to comment.