diff --git a/.jvmopts b/.jvmopts index 83ed6fb401..0ca1262c38 100644 --- a/.jvmopts +++ b/.jvmopts @@ -1,4 +1,3 @@ -# see https://weblogs.java.net/blog/kcpeppe/archive/2013/12/11/case-study-jvm-hotspot-flags -Dfile.encoding=UTF8 -Xms1G -Xmx6G @@ -6,7 +5,5 @@ -XX:ReservedCodeCacheSize=250M -XX:+TieredCompilation -XX:-UseGCOverheadLimit -# effectively adds GC to Perm space -XX:+CMSClassUnloadingEnabled -# must be enabled for CMSClassUnloadingEnabled to work -XX:+UseConcMarkSweepGC diff --git a/build.sbt b/build.sbt index b13c61d389..3bf80f81af 100644 --- a/build.sbt +++ b/build.sbt @@ -67,7 +67,7 @@ lazy val commonJsSettings = Seq( scalaJSStage in Global := FastOptStage, parallelExecution := false, requiresDOM := false, - jsEnv := NodeJSEnv().value, + jsEnv := new org.scalajs.jsenv.nodejs.NodeJSEnv(), // Only used for scala.js for now botBuild := scala.sys.env.get("TRAVIS").isDefined, // batch mode decreases the amount of memory needed to compile scala.js code diff --git a/core/src/main/scala/cats/data/EitherT.scala b/core/src/main/scala/cats/data/EitherT.scala index c9e5e3a531..b95c67df0e 100644 --- a/core/src/main/scala/cats/data/EitherT.scala +++ b/core/src/main/scala/cats/data/EitherT.scala @@ -175,7 +175,7 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { * scala> val v1: Validated[NonEmptyList[Error], Int] = Validated.invalidNel("error 1") * scala> val v2: Validated[NonEmptyList[Error], Int] = Validated.invalidNel("error 2") * scala> val eithert: EitherT[Option, Error, Int] = EitherT.leftT[Option, Int]("error 3") - * scala> eithert.withValidated { v3 => (v1 |@| v2 |@| v3.toValidatedNel).map { case (i, j, k) => i + j + k } } + * scala> eithert.withValidated { v3 => (v1, v2, v3.toValidatedNel).mapN { case (i, j, k) => i + j + k } } * res0: EitherT[Option, NonEmptyList[Error], Int] = EitherT(Some(Left(NonEmptyList(error 1, error 2, error 3)))) * }}} */ diff --git a/core/src/main/scala/cats/data/OneAnd.scala b/core/src/main/scala/cats/data/OneAnd.scala index 8e7728004c..9d85b8d8e5 100644 --- a/core/src/main/scala/cats/data/OneAnd.scala +++ b/core/src/main/scala/cats/data/OneAnd.scala @@ -229,10 +229,10 @@ private[data] trait OneAndLowPriority3 extends OneAndLowPriority2 { implicit def catsDataNonEmptyTraverseForOneAnd[F[_]](implicit F: Traverse[F], F2: MonadCombine[F]): NonEmptyTraverse[OneAnd[F, ?]] = new NonEmptyReducible[OneAnd[F, ?], F] with NonEmptyTraverse[OneAnd[F, ?]] { def nonEmptyTraverse[G[_], A, B](fa: OneAnd[F, A])(f: (A) => G[B])(implicit G: Apply[G]): G[OneAnd[F, B]] = { - import cats.syntax.cartesian._ + import cats.syntax.apply._ fa.map(a => Apply[G].map(f(a))(OneAnd(_, F2.empty[B])))(F) - .reduceLeft(((acc, a) => (acc |@| a).map((x: OneAnd[F, B], y: OneAnd[F, B]) => x.combine(y)))) + .reduceLeft(((acc, a) => (acc, a).mapN((x: OneAnd[F, B], y: OneAnd[F, B]) => x.combine(y)))) } diff --git a/core/src/main/scala/cats/data/Tuple2K.scala b/core/src/main/scala/cats/data/Tuple2K.scala index 7543da0172..1c1b5c1c51 100644 --- a/core/src/main/scala/cats/data/Tuple2K.scala +++ b/core/src/main/scala/cats/data/Tuple2K.scala @@ -2,7 +2,6 @@ package cats package data import cats.functor.Contravariant -import cats.syntax.cartesian._ /** * [[Tuple2K]] is a product to two independent functor values. @@ -159,8 +158,8 @@ private[data] sealed trait Tuple2KTraverse[F[_], G[_]] extends Traverse[λ[α => def F: Traverse[F] def G: Traverse[G] - override def traverse[H[_]: Applicative, A, B](fa: Tuple2K[F, G, A])(f: A => H[B]): H[Tuple2K[F, G, B]] = - (F.traverse(fa.first)(f) |@| G.traverse(fa.second)(f)).map(Tuple2K(_, _)) + override def traverse[H[_], A, B](fa: Tuple2K[F, G, A])(f: A => H[B])(implicit H: Applicative[H]): H[Tuple2K[F, G, B]] = + H.map2(F.traverse(fa.first)(f), G.traverse(fa.second)(f))(Tuple2K(_, _)) } private[data] sealed trait Tuple2KMonadCombine[F[_], G[_]] extends MonadCombine[λ[α => Tuple2K[F, G, α]]] diff --git a/core/src/main/scala/cats/syntax/all.scala b/core/src/main/scala/cats/syntax/all.scala index 0cf3dad050..5352b51183 100644 --- a/core/src/main/scala/cats/syntax/all.scala +++ b/core/src/main/scala/cats/syntax/all.scala @@ -43,7 +43,6 @@ trait AllSyntax with TraverseFilterSyntax with TraverseSyntax with NonEmptyTraverseSyntax - with TupleSyntax with ValidatedSyntax with VectorSyntax with WriterSyntax diff --git a/core/src/main/scala/cats/syntax/apply.scala b/core/src/main/scala/cats/syntax/apply.scala index 17f9685aaf..32854d57c7 100644 --- a/core/src/main/scala/cats/syntax/apply.scala +++ b/core/src/main/scala/cats/syntax/apply.scala @@ -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 diff --git a/core/src/main/scala/cats/syntax/cartesian.scala b/core/src/main/scala/cats/syntax/cartesian.scala index c5c4b6bb79..abb69f05ad 100644 --- a/core/src/main/scala/cats/syntax/cartesian.scala +++ b/core/src/main/scala/cats/syntax/cartesian.scala @@ -10,6 +10,8 @@ trait CartesianSyntax { } abstract class CartesianOps[F[_], A] extends Cartesian.Ops[F, A] { + + @deprecated("Replaced by an apply syntax, e.g. instead of (a |@| b).map(...) use (a, b).mapN(...)", "1.0.0-MF") final def |@|[B](fb: F[B]): CartesianBuilder[F]#CartesianBuilder2[A, B] = new CartesianBuilder[F] |@| self |@| fb diff --git a/core/src/main/scala/cats/syntax/package.scala b/core/src/main/scala/cats/syntax/package.scala index 7c7ab4285e..bef1b4174f 100644 --- a/core/src/main/scala/cats/syntax/package.scala +++ b/core/src/main/scala/cats/syntax/package.scala @@ -43,7 +43,6 @@ package object syntax { object traverse extends TraverseSyntax object nonEmptyTraverse extends NonEmptyTraverseSyntax object traverseFilter extends TraverseFilterSyntax - object tuple extends TupleSyntax object validated extends ValidatedSyntax object vector extends VectorSyntax object writer extends WriterSyntax diff --git a/core/src/main/scala/cats/syntax/tuple.scala b/core/src/main/scala/cats/syntax/tuple.scala deleted file mode 100644 index 2448e6f3bc..0000000000 --- a/core/src/main/scala/cats/syntax/tuple.scala +++ /dev/null @@ -1,4 +0,0 @@ -package cats -package syntax - -trait TupleSyntax extends TupleCartesianSyntax diff --git a/docs/src/main/tut/datatypes/freeapplicative.md b/docs/src/main/tut/datatypes/freeapplicative.md index 5c0448c24f..3c7788cdfa 100644 --- a/docs/src/main/tut/datatypes/freeapplicative.md +++ b/docs/src/main/tut/datatypes/freeapplicative.md @@ -46,7 +46,7 @@ of a for-comprehension. We can however still use `Applicative` syntax provided b ```tut:silent import cats.implicits._ -val prog: Validation[Boolean] = (size(5) |@| hasNumber).map { case (l, r) => l && r} +val prog: Validation[Boolean] = (size(5), hasNumber).mapN { case (l, r) => l && r} ``` As it stands, our program is just an instance of a data structure - nothing has happened @@ -139,7 +139,7 @@ def logValidation[A](validation: Validation[A]): List[String] = ```tut:book logValidation(prog) logValidation(size(5) *> hasNumber *> size(10)) -logValidation((hasNumber |@| size(3)).map(_ || _)) +logValidation((hasNumber, size(3)).mapN(_ || _)) ``` ### Why not both? diff --git a/docs/src/main/tut/datatypes/validated.md b/docs/src/main/tut/datatypes/validated.md index 55c7303940..bb258b147b 100644 --- a/docs/src/main/tut/datatypes/validated.md +++ b/docs/src/main/tut/datatypes/validated.md @@ -205,7 +205,7 @@ implicit def validatedApplicative[E : Semigroup]: Applicative[Validated[E, ?]] = ``` Awesome! And now we also get access to all the goodness of `Applicative`, which includes `map{2-22}`, as well as the -`Cartesian` syntax `|@|`. +`Cartesian` tuple syntax. We can now easily ask for several bits of configuration and get any and all errors returned back. diff --git a/docs/src/main/tut/faq.md b/docs/src/main/tut/faq.md index e1219525ff..a2458a9a28 100644 --- a/docs/src/main/tut/faq.md +++ b/docs/src/main/tut/faq.md @@ -203,7 +203,6 @@ All other symbols can be imported with `import cats.implicits._` | Symbol | Name | Nickname | Type Class | Signature | | -------------------------------- | ---------------------- | ---------------- | ----------------------- | --------------------------------------------------------- | -| fa |@| fb | Cartesian builder | Cinnabon, scream | `Cartesian[F[_]]` | |@|(fa: F[A])(fb: F[B]): F[(A, B)] | | `fa *> fb` | right apply | | `Cartesian[F[_]]` | `*>(fa: F[A])(fb: F[B]): F[A]` | | `fa <* fb` | left apply | | `Cartesian[F[_]]` | `<*(fa: F[A])(fb: F[B]): F[B]` | | `x === y` | equals | | `Eq[A]` | `eqv(x: A, y: A): Boolean` | diff --git a/docs/src/main/tut/typeclasses/applicative.md b/docs/src/main/tut/typeclasses/applicative.md index b4c26cf9d0..4c6cea3ef5 100644 --- a/docs/src/main/tut/typeclasses/applicative.md +++ b/docs/src/main/tut/typeclasses/applicative.md @@ -264,15 +264,15 @@ val o2: Option[String] = Some("hello") ``` ```tut:book -(o1 |@| o2).map((i: Int, s: String) => i.toString ++ s) -(o1 |@| o2).tupled +(o1, o2).mapN((i: Int, s: String) => i.toString ++ s) +(o1, o2).tupled ``` The second expects the effects in a tuple and works by enriching syntax on top of the existing `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 diff --git a/docs/src/main/tut/typeclasses/invariantmonoidal.md b/docs/src/main/tut/typeclasses/invariantmonoidal.md index 4525cd6655..fbf103df8f 100644 --- a/docs/src/main/tut/typeclasses/invariantmonoidal.md +++ b/docs/src/main/tut/typeclasses/invariantmonoidal.md @@ -52,8 +52,8 @@ import cats.implicits._ case class Foo(a: String, c: List[Double]) implicit val fooSemigroup: Semigroup[Foo] = ( - (implicitly[Semigroup[String]] |@| implicitly[Semigroup[List[Double]]]) - .imap(Foo.apply)(Function.unlift(Foo.unapply)) + (implicitly[Semigroup[String]], implicitly[Semigroup[List[Double]]]) + .imapN(Foo.apply)(Function.unlift(Foo.unapply)) ) ``` @@ -105,7 +105,7 @@ trait CCProduct { 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 = @@ -163,15 +163,15 @@ def numericSystemCodec(base: Int): CsvCodec[Int] = case class BinDec(binary: Int, decimal: Int) val binDecCodec: CsvCodec[BinDec] = ( - (numericSystemCodec(2) |@| numericSystemCodec(10)) - .imap(BinDec.apply)(Function.unlift(BinDec.unapply)) + (numericSystemCodec(2), numericSystemCodec(10)) + .imapN(BinDec.apply)(Function.unlift(BinDec.unapply)) ) case class Foo(name: String, bd1: BinDec, bd2: BinDec) val fooCodec: CsvCodec[Foo] = ( - (stringCodec |@| binDecCodec |@| binDecCodec) - .imap(Foo.apply)(Function.unlift(Foo.unapply)) + (stringCodec, binDecCodec, binDecCodec) + .imapN(Foo.apply)(Function.unlift(Foo.unapply)) ) ``` diff --git a/free/src/test/scala/cats/free/FreeApplicativeTests.scala b/free/src/test/scala/cats/free/FreeApplicativeTests.scala index 1e6467900b..afdef68074 100644 --- a/free/src/test/scala/cats/free/FreeApplicativeTests.scala +++ b/free/src/test/scala/cats/free/FreeApplicativeTests.scala @@ -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") { diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index bbc587aecc..e3eeb9c1e0 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -136,6 +136,7 @@ object Boilerplate { | |import cats.functor.{Contravariant, Invariant} | + |@deprecated("replaced by apply syntax", "1.0.0-MF") |private[syntax] final class CartesianBuilder[F[_]] { | def |@|[A](a: F[A]) = new CartesianBuilder1(a) | @@ -238,15 +239,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 @@ -255,13 +262,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) -} | diff --git a/tests/src/test/scala/cats/tests/CsvCodecInvariantMonoidalTests.scala b/tests/src/test/scala/cats/tests/CsvCodecInvariantMonoidalTests.scala index 3363c32fc8..9137f8d174 100644 --- a/tests/src/test/scala/cats/tests/CsvCodecInvariantMonoidalTests.scala +++ b/tests/src/test/scala/cats/tests/CsvCodecInvariantMonoidalTests.scala @@ -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} @@ -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 = diff --git a/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala b/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala index fcd3d9c9b9..7af05125a6 100644 --- a/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala +++ b/tests/src/test/scala/cats/tests/ReaderWriterStateTTests.scala @@ -204,7 +204,7 @@ class ReaderWriterStateTTests extends CatsSuite { test("runEmpty, runEmptyS, runEmptyA and runEmptyL are consistent") { forAll { (f: ReaderWriterStateT[Option, String, String, String, Int], c: String) => - (f.runEmptyL(c) |@| f.runEmptyS(c) |@| f.runEmptyA(c)).tupled should === (f.runEmpty(c)) + (f.runEmptyL(c), f.runEmptyS(c), f.runEmptyA(c)).tupled should === (f.runEmpty(c)) } } diff --git a/tests/src/test/scala/cats/tests/SyntaxTests.scala b/tests/src/test/scala/cats/tests/SyntaxTests.scala index d97902b7fb..f99472a8dc 100644 --- a/tests/src/test/scala/cats/tests/SyntaxTests.scala +++ b/tests/src/test/scala/cats/tests/SyntaxTests.scala @@ -193,28 +193,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 = { @@ -293,38 +302,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) - } } /**