Skip to content

Commit

Permalink
Deprecate CartesianBuilder, finish up #1487 (#1745)
Browse files Browse the repository at this point in the history
* Apply syntax for tuples, fixes #1363

* fix feedback and build error
  • Loading branch information
kailuowang authored Jul 2, 2017
1 parent 44021d6 commit 99b543b
Show file tree
Hide file tree
Showing 20 changed files with 66 additions and 89 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 build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
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.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))))
* }}}
*/
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/data/OneAnd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))))
}


Expand Down
5 changes: 2 additions & 3 deletions core/src/main/scala/cats/data/Tuple2K.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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, α]]]
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 @@ -43,7 +43,6 @@ trait AllSyntax
with TraverseFilterSyntax
with TraverseSyntax
with NonEmptyTraverseSyntax
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
2 changes: 2 additions & 0 deletions core/src/main/scala/cats/syntax/cartesian.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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

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 @@ -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
Expand Down
4 changes: 0 additions & 4 deletions core/src/main/scala/cats/syntax/tuple.scala

This file was deleted.

4 changes: 2 additions & 2 deletions docs/src/main/tut/datatypes/freeapplicative.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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?
Expand Down
2 changes: 1 addition & 1 deletion docs/src/main/tut/datatypes/validated.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
1 change: 0 additions & 1 deletion docs/src/main/tut/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,6 @@ All other symbols can be imported with `import cats.implicits._`

| Symbol | Name | Nickname | Type Class | Signature |
| -------------------------------- | ---------------------- | ---------------- | ----------------------- | --------------------------------------------------------- |
| <code>fa &#124;@&#124; fb</code> | Cartesian builder | Cinnabon, scream | `Cartesian[F[_]]` | <code>&#124;@&#124;(fa: F[A])(fb: F[B]): F[(A, B)]</code> |
| `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` |
Expand Down
6 changes: 3 additions & 3 deletions docs/src/main/tut/typeclasses/applicative.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 7 additions & 7 deletions docs/src/main/tut/typeclasses/invariantmonoidal.md
Original file line number Diff line number Diff line change
Expand Up @@ -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))
)
```

Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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))
)
```

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
19 changes: 14 additions & 5 deletions project/Boilerplate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
|
Expand Down Expand Up @@ -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
Expand All @@ -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)
-}
|
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
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
}

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 @@ -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 = {
Expand Down Expand Up @@ -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)
}
}

/**
Expand Down

0 comments on commit 99b543b

Please sign in to comment.