From bacdff3c0a49b0776384e91d4200cd7775d32344 Mon Sep 17 00:00:00 2001 From: Kailuo Wang Date: Thu, 13 Apr 2017 17:38:20 -0400 Subject: [PATCH 1/5] standardized to partial unification as SI-2712 fix --- core/src/main/scala/cats/Foldable.scala | 45 ------------------- core/src/main/scala/cats/Traverse.scala | 36 --------------- core/src/main/scala/cats/data/Const.scala | 11 ++--- core/src/main/scala/cats/data/EitherT.scala | 6 +-- core/src/main/scala/cats/data/Func.scala | 3 -- core/src/main/scala/cats/syntax/apply.scala | 12 +---- .../main/scala/cats/syntax/cartesian.scala | 10 +---- .../main/scala/cats/syntax/coflatMap.scala | 9 +--- core/src/main/scala/cats/syntax/comonad.scala | 9 +--- .../scala/cats/syntax/contravariant.scala | 10 +---- core/src/main/scala/cats/syntax/flatMap.scala | 10 +---- .../src/main/scala/cats/syntax/foldable.scala | 10 +---- core/src/main/scala/cats/syntax/functor.scala | 9 +--- .../scala/cats/syntax/functorFilter.scala | 10 +---- .../main/scala/cats/syntax/invariant.scala | 10 +---- .../main/scala/cats/syntax/monadFilter.scala | 9 +--- .../main/scala/cats/syntax/reducible.scala | 10 +---- .../main/scala/cats/syntax/semigroupk.scala | 11 +---- .../main/scala/cats/syntax/transLift.scala | 3 +- .../src/main/scala/cats/syntax/traverse.scala | 10 +---- .../scala/cats/syntax/traverseFilter.scala | 10 +---- docs/src/main/tut/faq.md | 13 +++++- docs/src/main/tut/typeclasses/functor.md | 2 +- free/src/main/scala/cats/free/FreeT.scala | 4 -- .../src/test/scala/cats/free/FreeTTests.scala | 6 --- project/plugins.sbt | 1 + .../test/scala/cats/tests/KleisliTests.scala | 5 +-- .../src/test/scala/cats/tests/MonadTest.scala | 6 +-- .../test/scala/cats/tests/NestedTests.scala | 12 +---- .../test/scala/cats/tests/OptionTTests.scala | 15 +------ .../scala/cats/tests/RegressionTests.scala | 18 ++++---- .../test/scala/cats/tests/StateTTests.scala | 2 +- .../test/scala/cats/tests/UnapplyTests.scala | 28 +++++++----- .../test/scala/cats/tests/WordCountTest.scala | 4 +- .../test/scala/cats/tests/WriterTTests.scala | 3 -- 35 files changed, 72 insertions(+), 300 deletions(-) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index 46fac29fea..641ef1379d 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -231,30 +231,6 @@ import simulacrum.typeclass G.map2Eval(f(a), acc) { (_, _) => () } }.value - /** - * Behaves like traverse_, but uses [[Unapply]] to find the - * [[Applicative]] instance for `G` - used when `G` is a - * type constructor with two or more parameters such as [[scala.util.Either]] - * - * {{{ - * scala> import cats.implicits._ - * scala> def parseInt(s: String): Either[String, Int] = - * | try { Right(s.toInt) } - * | catch { case _: NumberFormatException => Left("boo") } - * scala> val F = Foldable[List] - * scala> F.traverseU_(List("333", "444"))(parseInt) - * res0: Either[String, Unit] = Right(()) - * scala> F.traverseU_(List("333", "zzz"))(parseInt) - * res1: Either[String, Unit] = Left(boo) - * }}} - * - * Note that using `traverse_` instead of `traverseU_` would not compile without - * explicitly passing in the type parameters - the type checker has trouble - * inferring the appropriate instance. - */ - def traverseU_[A, GB](fa: F[A])(f: A => GB)(implicit U: Unapply[Applicative, GB]): U.M[Unit] = - traverse_(fa)(f.andThen(U.subst))(U.TC) - /** * Sequence `F[G[A]]` using `Applicative[G]`. * @@ -275,27 +251,6 @@ import simulacrum.typeclass def sequence_[G[_]: Applicative, A](fga: F[G[A]]): G[Unit] = traverse_(fga)(identity) - /** - * Behaves like sequence_, but uses [[Unapply]] to find the - * [[Applicative]] instance for `G` - used when `G` is a - * type constructor with two or more parameters such as [[scala.util.Either]] - * - * {{{ - * scala> import cats.implicits._ - * scala> val F = Foldable[List] - * scala> F.sequenceU_(List(Either.right[String, Int](333), Right(444))) - * res0: Either[String, Unit] = Right(()) - * scala> F.sequenceU_(List(Either.right[String, Int](333), Left("boo"))) - * res1: Either[String, Unit] = Left(boo) - * }}} - * - * Note that using `sequence_` instead of `sequenceU_` would not compile without - * explicitly passing in the type parameters - the type checker has trouble - * inferring the appropriate instance. - */ - def sequenceU_[GA](fa: F[GA])(implicit U: Unapply[Applicative, GA]): U.M[Unit] = - traverseU_(fa)(identity) - /** * Fold implemented using the given `MonoidK[G]` instance. * diff --git a/core/src/main/scala/cats/Traverse.scala b/core/src/main/scala/cats/Traverse.scala index 32e83215cb..24015db6b9 100644 --- a/core/src/main/scala/cats/Traverse.scala +++ b/core/src/main/scala/cats/Traverse.scala @@ -32,24 +32,6 @@ import simulacrum.typeclass */ def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B]] - /** - * Behaves just like traverse, but uses [[Unapply]] to find the - * Applicative instance for G. - * - * Example: - * {{{ - * scala> import cats.implicits._ - * scala> def parseInt(s: String): Either[String, Int] = Either.catchOnly[NumberFormatException](s.toInt).leftMap(_ => "no number") - * scala> val ns = List("1", "2", "3") - * scala> ns.traverseU(parseInt) - * res0: Either[String, List[Int]] = Right(List(1, 2, 3)) - * scala> ns.traverse[Either[String, ?], Int](parseInt) - * res1: Either[String, List[Int]] = Right(List(1, 2, 3)) - * }}} - */ - def traverseU[A, GB](fa: F[A])(f: A => GB)(implicit U: Unapply[Applicative, GB]): U.M[F[U.A]] = - U.TC.traverse(fa)(a => U.subst(f(a)))(this) - /** * A traverse followed by flattening the inner result. * @@ -101,24 +83,6 @@ import simulacrum.typeclass def flatSequence[G[_], A](fgfa: F[G[F[A]]])(implicit G: Applicative[G], F: FlatMap[F]): G[F[A]] = G.map(sequence(fgfa))(F.flatten) - /** - * Behaves just like sequence, but uses [[Unapply]] to find the - * Applicative instance for G. - * - * Example: - * {{{ - * scala> import cats.data.{Validated, ValidatedNel} - * scala> import cats.implicits._ - * scala> val x: List[ValidatedNel[String, Int]] = List(Validated.valid(1), Validated.invalid("a"), Validated.invalid("b")).map(_.toValidatedNel) - * scala> x.sequenceU - * res0: cats.data.ValidatedNel[String,List[Int]] = Invalid(NonEmptyList(a, b)) - * scala> x.sequence[ValidatedNel[String, ?], Int] - * res1: cats.data.ValidatedNel[String,List[Int]] = Invalid(NonEmptyList(a, b)) - * }}} - */ - def sequenceU[GA](fga: F[GA])(implicit U: Unapply[Applicative, GA]): U.M[F[U.A]] = - traverse(fga)(U.subst)(U.TC) - def compose[G[_]: Traverse]: Traverse[λ[α => F[G[α]]]] = new ComposedTraverse[F, G] { val F = self diff --git a/core/src/main/scala/cats/data/Const.scala b/core/src/main/scala/cats/data/Const.scala index 65b0132ce0..a6e5646c7b 100644 --- a/core/src/main/scala/cats/data/Const.scala +++ b/core/src/main/scala/cats/data/Const.scala @@ -6,15 +6,16 @@ import cats.functor.Contravariant /** * [[Const]] is a phantom type, it does not contain a value of its second type parameter `B` * [[Const]] can be seen as a type level version of `Function.const[A, B]: A => B => A` + * B is set covariant to help type inference. */ -final case class Const[A, B](getConst: A) { +final case class Const[A, +B](getConst: A) { /** * changes the type of the second type parameter */ def retag[C]: Const[A, C] = this.asInstanceOf[Const[A, C]] - def combine(that: Const[A, B])(implicit A: Semigroup[A]): Const[A, B] = + def combine[BB >: B](that: Const[A, BB])(implicit A: Semigroup[A]): Const[A, BB] = Const(A.combine(getConst, that.getConst)) def traverseFilter[F[_], C](f: B => F[Option[C]])(implicit F: Applicative[F]): F[Const[A, C]] = @@ -23,13 +24,13 @@ final case class Const[A, B](getConst: A) { def traverse[F[_], C](f: B => F[C])(implicit F: Applicative[F]): F[Const[A, C]] = F.pure(retag[C]) - def ===(that: Const[A, B])(implicit A: Eq[A]): Boolean = + def ===[BB >: B](that: Const[A, BB])(implicit A: Eq[A]): Boolean = A.eqv(getConst, that.getConst) - def partialCompare(that: Const[A, B])(implicit A: PartialOrder[A]): Double = + def partialCompare[BB >: B](that: Const[A, BB])(implicit A: PartialOrder[A]): Double = A.partialCompare(getConst, that.getConst) - def compare(that: Const[A, B])(implicit A: Order[A]): Int = + def compare[BB >: B](that: Const[A, BB])(implicit A: Order[A]): Int = A.compare(getConst, that.getConst) def show(implicit A: Show[A]): String = diff --git a/core/src/main/scala/cats/data/EitherT.scala b/core/src/main/scala/cats/data/EitherT.scala index 1b51488624..b292db8b2a 100644 --- a/core/src/main/scala/cats/data/EitherT.scala +++ b/core/src/main/scala/cats/data/EitherT.scala @@ -195,17 +195,13 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { * | EitherT(List(Either.right(_.toString), Either.left("error"))) * scala> val fa: EitherT[List, String, Int] = * | EitherT(List(Either.right(1), Either.right(2))) - * scala> type ErrorOr[A] = Either[String, A] - * scala> type ListErrorOr[A] = Nested[List, ErrorOr, A] + * scala> type ListErrorOr[A] = Nested[List, Either[String, ?], A] * scala> ff.ap(fa) * res0: EitherT[List,String,String] = EitherT(List(Right(1), Right(2), Left(error))) * scala> EitherT((ff.toNested: ListErrorOr[Int => String]).ap(fa.toNested: ListErrorOr[Int]).value) * res1: EitherT[List,String,String] = EitherT(List(Right(1), Right(2), Left(error), Left(error))) * }}} * - * Note that we need the `ErrorOr` type alias above because otherwise we can't use the - * syntax function `ap` on `Nested[List, Either[A, ?], B]`. This won't be needed after cats has - * decided [[https://github.com/typelevel/cats/issues/1073 how to handle the SI-2712 fix]]. */ def toNested: Nested[F, Either[A, ?], B] = Nested[F, Either[A, ?], B](value) diff --git a/core/src/main/scala/cats/data/Func.scala b/core/src/main/scala/cats/data/Func.scala index 0f3535aa06..350e50329a 100644 --- a/core/src/main/scala/cats/data/Func.scala +++ b/core/src/main/scala/cats/data/Func.scala @@ -28,9 +28,6 @@ object Func extends FuncInstances { def run: A => F[B] = run0 } - /** applicative function using [[Unapply]]. */ - def appFuncU[A, R](f: A => R)(implicit RR: Unapply[Applicative, R]): AppFunc[RR.M, A, RR.A] = - appFunc({ a: A => RR.subst(f(a)) })(RR.TC) } private[data] abstract class FuncInstances extends FuncInstances0 { diff --git a/core/src/main/scala/cats/syntax/apply.scala b/core/src/main/scala/cats/syntax/apply.scala index 2671087bf1..17f9685aaf 100644 --- a/core/src/main/scala/cats/syntax/apply.scala +++ b/core/src/main/scala/cats/syntax/apply.scala @@ -1,16 +1,8 @@ package cats package syntax -private[syntax] trait ApplySyntax1 { - implicit final def catsSyntaxUApply[FA](fa: FA)(implicit U: Unapply[Apply, FA]): Apply.Ops[U.M, U.A] = - new Apply.Ops[U.M, U.A] { - val self = U.subst(fa) - val typeClassInstance = U.TC - } -} - -trait ApplySyntax extends ApplySyntax1 { - implicit def catsSyntaxApply[F[_], A](fa: F[A])(implicit F: Apply[F]): Apply.Ops[F, A] = +trait ApplySyntax { + 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 val typeClassInstance = F diff --git a/core/src/main/scala/cats/syntax/cartesian.scala b/core/src/main/scala/cats/syntax/cartesian.scala index efff7b4396..c5c4b6bb79 100644 --- a/core/src/main/scala/cats/syntax/cartesian.scala +++ b/core/src/main/scala/cats/syntax/cartesian.scala @@ -1,15 +1,7 @@ package cats package syntax -private[syntax] trait CartesianSyntax1 { - implicit final def catsSyntaxUCartesian[FA](fa: FA)(implicit U: Unapply[Cartesian, FA]): CartesianOps[U.M, U.A] = - new CartesianOps[U.M, U.A] { - val self = U.subst(fa) - val typeClassInstance = U.TC - } -} - -trait CartesianSyntax extends CartesianSyntax1 { +trait CartesianSyntax { implicit final def catsSyntaxCartesian[F[_], A](fa: F[A])(implicit F: Cartesian[F]): CartesianOps[F, A] = new CartesianOps[F, A] { val self = fa diff --git a/core/src/main/scala/cats/syntax/coflatMap.scala b/core/src/main/scala/cats/syntax/coflatMap.scala index e394677da4..37d860ce1c 100644 --- a/core/src/main/scala/cats/syntax/coflatMap.scala +++ b/core/src/main/scala/cats/syntax/coflatMap.scala @@ -1,11 +1,4 @@ package cats package syntax -private[syntax] trait CoflatMapSyntax1 { - implicit final def catsSyntaxUCoflatMap[FA](fa: FA)(implicit U: Unapply[CoflatMap, FA]): CoflatMap.Ops[U.M, U.A] = new CoflatMap.Ops[U.M, U.A] { - val self = U.subst(fa) - val typeClassInstance = U.TC - } -} - -trait CoflatMapSyntax extends CoflatMap.ToCoflatMapOps with CoflatMapSyntax1 +trait CoflatMapSyntax extends CoflatMap.ToCoflatMapOps diff --git a/core/src/main/scala/cats/syntax/comonad.scala b/core/src/main/scala/cats/syntax/comonad.scala index cbeaf7bb0f..77d413ebcc 100644 --- a/core/src/main/scala/cats/syntax/comonad.scala +++ b/core/src/main/scala/cats/syntax/comonad.scala @@ -1,12 +1,5 @@ package cats package syntax -private[syntax] trait ComonadSyntax1 { - implicit final def catsSyntaxUComonad[FA](fa: FA)(implicit U: Unapply[Comonad, FA]): Comonad.Ops[U.M, U.A] = - new Comonad.Ops[U.M, U.A] { - val self = U.subst(fa) - val typeClassInstance = U.TC - } -} +trait ComonadSyntax extends Comonad.ToComonadOps -trait ComonadSyntax extends Comonad.ToComonadOps with ComonadSyntax1 diff --git a/core/src/main/scala/cats/syntax/contravariant.scala b/core/src/main/scala/cats/syntax/contravariant.scala index 7eda421d6b..996d489adf 100644 --- a/core/src/main/scala/cats/syntax/contravariant.scala +++ b/core/src/main/scala/cats/syntax/contravariant.scala @@ -3,13 +3,5 @@ package syntax import cats.functor.Contravariant -private[syntax] trait ContravariantSyntax1 { - implicit final def catsSyntaxUContravariant[FA](fa: FA)(implicit U: Unapply[Contravariant, FA]): Contravariant.Ops[U.M, U.A] = - new Contravariant.Ops[U.M, U.A] { - val self = U.subst(fa) - val typeClassInstance = U.TC - } -} - -trait ContravariantSyntax extends Contravariant.ToContravariantOps with ContravariantSyntax1 +trait ContravariantSyntax extends Contravariant.ToContravariantOps diff --git a/core/src/main/scala/cats/syntax/flatMap.scala b/core/src/main/scala/cats/syntax/flatMap.scala index 596019e860..5fcfc8a339 100644 --- a/core/src/main/scala/cats/syntax/flatMap.scala +++ b/core/src/main/scala/cats/syntax/flatMap.scala @@ -1,15 +1,7 @@ package cats package syntax -private[syntax] trait FlatMapSyntax1 { - implicit final def catsSyntaxUFlatMap[FA](fa: FA)(implicit U: Unapply[FlatMap, FA]): FlatMap.Ops[U.M, U.A] = - new FlatMap.Ops[U.M, U.A]{ - val self = U.subst(fa) - val typeClassInstance = U.TC - } -} - -trait FlatMapSyntax extends FlatMap.ToFlatMapOps with FlatMapSyntax1 { +trait FlatMapSyntax extends FlatMap.ToFlatMapOps { implicit final def catsSyntaxFlatten[F[_]: FlatMap, A](ffa: F[F[A]]): FlattenOps[F, A] = new FlattenOps[F, A](ffa) diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index 9a765f08f0..87902c3ca3 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -1,15 +1,7 @@ package cats package syntax -private[syntax] trait FoldableSyntax1 { - implicit final def catsSyntaxUFoldable[FA](fa: FA)(implicit U: Unapply[Foldable, FA]): Foldable.Ops[U.M, U.A] = - new Foldable.Ops[U.M, U.A] { - val self = U.subst(fa) - val typeClassInstance = U.TC - } -} - -trait FoldableSyntax extends Foldable.ToFoldableOps with FoldableSyntax1 { +trait FoldableSyntax extends Foldable.ToFoldableOps { implicit final def catsSyntaxNestedFoldable[F[_]: Foldable, G[_], A](fga: F[G[A]]): NestedFoldableOps[F, G, A] = new NestedFoldableOps[F, G, A](fga) } diff --git a/core/src/main/scala/cats/syntax/functor.scala b/core/src/main/scala/cats/syntax/functor.scala index 478299c92a..f8f4fb9fe7 100644 --- a/core/src/main/scala/cats/syntax/functor.scala +++ b/core/src/main/scala/cats/syntax/functor.scala @@ -1,12 +1,5 @@ package cats package syntax -private[syntax] trait FunctorSyntax1 { - implicit final def catsSyntaxUFunctor[FA](fa: FA)(implicit U: Unapply[Functor, FA]): Functor.Ops[U.M, U.A] = - new Functor.Ops[U.M, U.A]{ - val self = U.subst(fa) - val typeClassInstance = U.TC - } -} +trait FunctorSyntax extends Functor.ToFunctorOps -trait FunctorSyntax extends Functor.ToFunctorOps with FunctorSyntax1 diff --git a/core/src/main/scala/cats/syntax/functorFilter.scala b/core/src/main/scala/cats/syntax/functorFilter.scala index dfefedcce9..a80b6c2618 100644 --- a/core/src/main/scala/cats/syntax/functorFilter.scala +++ b/core/src/main/scala/cats/syntax/functorFilter.scala @@ -1,12 +1,4 @@ package cats package syntax -private[syntax] trait FunctorFilterSyntax1 { - implicit final def catsSyntaxUFunctorFilter[FA](fa: FA)(implicit U: Unapply[FunctorFilter, FA]): FunctorFilter.Ops[U.M, U.A] = - new FunctorFilter.Ops[U.M, U.A]{ - val self = U.subst(fa) - val typeClassInstance = U.TC - } -} - -trait FunctorFilterSyntax extends FunctorFilter.ToFunctorFilterOps with FunctorFilterSyntax1 +trait FunctorFilterSyntax extends FunctorFilter.ToFunctorFilterOps diff --git a/core/src/main/scala/cats/syntax/invariant.scala b/core/src/main/scala/cats/syntax/invariant.scala index 3f425c002c..7e5270f535 100644 --- a/core/src/main/scala/cats/syntax/invariant.scala +++ b/core/src/main/scala/cats/syntax/invariant.scala @@ -3,12 +3,4 @@ package syntax import cats.functor.Invariant -private[syntax] trait InvariantSyntax1 { - implicit final def catsSyntaxUInvariant[FA](fa: FA)(implicit U: Unapply[Invariant, FA]): Invariant.Ops[U.M, U.A] = - new Invariant.Ops[U.M, U.A] { - val self = U.subst(fa) - val typeClassInstance = U.TC - } -} - -trait InvariantSyntax extends Invariant.ToInvariantOps with InvariantSyntax1 +trait InvariantSyntax extends Invariant.ToInvariantOps diff --git a/core/src/main/scala/cats/syntax/monadFilter.scala b/core/src/main/scala/cats/syntax/monadFilter.scala index 8413fb64f5..ee9208eaaf 100644 --- a/core/src/main/scala/cats/syntax/monadFilter.scala +++ b/core/src/main/scala/cats/syntax/monadFilter.scala @@ -1,12 +1,5 @@ package cats package syntax -private[syntax] trait MonadFilterSyntax1 { - implicit final def catsSyntaxUMonadFilter[FA](fa: FA)(implicit U: Unapply[MonadFilter, FA]): MonadFilter.Ops[U.M, U.A] = - new MonadFilter.Ops[U.M, U.A] { - val self = U.subst(fa) - val typeClassInstance = U.TC - } -} +trait MonadFilterSyntax extends MonadFilter.ToMonadFilterOps -trait MonadFilterSyntax extends MonadFilter.ToMonadFilterOps with MonadFilterSyntax1 diff --git a/core/src/main/scala/cats/syntax/reducible.scala b/core/src/main/scala/cats/syntax/reducible.scala index a513d88415..10f4487410 100644 --- a/core/src/main/scala/cats/syntax/reducible.scala +++ b/core/src/main/scala/cats/syntax/reducible.scala @@ -1,15 +1,7 @@ package cats package syntax -private[syntax] trait ReducibleSyntax1 { - implicit final def catsSyntaxUReducible[FA](fa: FA)(implicit U: Unapply[Reducible, FA]): Reducible.Ops[U.M, U.A] = - new Reducible.Ops[U.M, U.A] { - val self = U.subst(fa) - val typeClassInstance = U.TC - } -} - -trait ReducibleSyntax extends Reducible.ToReducibleOps with ReducibleSyntax1 { +trait ReducibleSyntax extends Reducible.ToReducibleOps { implicit final def catsSyntaxNestedReducible[F[_]: Reducible, G[_], A](fga: F[G[A]]): NestedReducibleOps[F, G, A] = new NestedReducibleOps[F, G, A](fga) } diff --git a/core/src/main/scala/cats/syntax/semigroupk.scala b/core/src/main/scala/cats/syntax/semigroupk.scala index 39f05b546d..832501764a 100644 --- a/core/src/main/scala/cats/syntax/semigroupk.scala +++ b/core/src/main/scala/cats/syntax/semigroupk.scala @@ -1,13 +1,4 @@ package cats package syntax -private[syntax] trait SemigroupKSyntax1 { - // TODO: use simulacrum instances eventually - implicit final def catsSyntaxUSemigroup[FA](fa: FA)(implicit U: Unapply[SemigroupK, FA]): SemigroupK.Ops[U.M, U.A] = - new SemigroupK.Ops[U.M, U.A] { - val self = U.subst(fa) - val typeClassInstance = U.TC - } -} - -trait SemigroupKSyntax extends SemigroupK.ToSemigroupKOps with SemigroupKSyntax1 +trait SemigroupKSyntax extends SemigroupK.ToSemigroupKOps diff --git a/core/src/main/scala/cats/syntax/transLift.scala b/core/src/main/scala/cats/syntax/transLift.scala index f85ed47835..5f3c228c42 100644 --- a/core/src/main/scala/cats/syntax/transLift.scala +++ b/core/src/main/scala/cats/syntax/transLift.scala @@ -2,8 +2,7 @@ package cats package syntax trait TransLiftSyntax { - implicit final def catsSyntaxTransLift[E](ma: E)(implicit U: Unapply[Trivial.PH1, E]): TransLiftOps[U.M, U.A] = - new TransLiftOps(U.subst(ma)) + implicit final def catsSyntaxTransLift[M0[_], A](ma: M0[A]): TransLiftOps[M0, A] = new TransLiftOps(ma) } final class TransLiftOps[M0[_], A](val ma: M0[A]) extends AnyVal { diff --git a/core/src/main/scala/cats/syntax/traverse.scala b/core/src/main/scala/cats/syntax/traverse.scala index f004d7ba98..9205507f3b 100644 --- a/core/src/main/scala/cats/syntax/traverse.scala +++ b/core/src/main/scala/cats/syntax/traverse.scala @@ -1,12 +1,4 @@ package cats package syntax -private[syntax] trait TraverseSyntax1 { - implicit final def catsSyntaxUTraverse[FA](fa: FA)(implicit U: Unapply[Traverse, FA]): Traverse.Ops[U.M, U.A] = - new Traverse.Ops[U.M, U.A]{ - val self = U.subst(fa) - val typeClassInstance = U.TC - } -} - -trait TraverseSyntax extends Traverse.ToTraverseOps with TraverseSyntax1 +trait TraverseSyntax extends Traverse.ToTraverseOps diff --git a/core/src/main/scala/cats/syntax/traverseFilter.scala b/core/src/main/scala/cats/syntax/traverseFilter.scala index 6b24109251..794caeddee 100644 --- a/core/src/main/scala/cats/syntax/traverseFilter.scala +++ b/core/src/main/scala/cats/syntax/traverseFilter.scala @@ -1,12 +1,4 @@ package cats package syntax -trait TraverseFilterSyntax extends TraverseFilter.ToTraverseFilterOps with TraverseFilterSyntax1 - -private[syntax] trait TraverseFilterSyntax1 { - implicit final def catsSyntaxUTraverseFilter[FA](fa: FA)(implicit U: Unapply[TraverseFilter, FA]): TraverseFilter.Ops[U.M, U.A] = - new TraverseFilter.Ops[U.M, U.A]{ - val self = U.subst(fa) - val typeClassInstance = U.TC - } -} +trait TraverseFilterSyntax extends TraverseFilter.ToTraverseFilterOps diff --git a/docs/src/main/tut/faq.md b/docs/src/main/tut/faq.md index 11bbb7dd43..cd71bb292d 100644 --- a/docs/src/main/tut/faq.md +++ b/docs/src/main/tut/faq.md @@ -11,7 +11,9 @@ position: 4 * [What imports do I need?](#what-imports) * [Where is right-biased `Either`?](#either) + * [Why is the compiler having trouble with types with more than one type parameters?](#si-2712) * [Why can't the compiler find implicit instances for Future?](#future-instances) + * [Why is some example code not compiling for me?](#example-compile) * [How can I turn my List of `` into a `` of a list?](#traverse) * [Where is `ListT`?](#listt) * [Where is `IO`/`Task`?](#task) @@ -47,13 +49,22 @@ There are a few minor mismatches between `Xor` and `Either`. For example, in som Similarly, `cats.data.XorT` has been replaced with `cats.data.EitherT`, although since this is a type defined in Cats, you don't need to import syntax or instances for it (although you may need imports for the underlying monad). +## Why is the compiler having trouble with types with more than one type parameters? + +When you encounter a situation where the same code works fine with a type with one type parameter, e.g. List[A], but doesn't work with types with more than one, e.g. Either[A, B], you probably hit [SI-2712](https://issues.scala-lang.org/browse/SI-2712). Without going into the details, it's highly recommended to enable a partial SI-2712 fix in your project. The easiest way to achieve that is through this [sbt plugin](https://github.com/fiadliel/sbt-partial-unification). +Cats used to provide mitigation to this issue semi-transparently, but given the fact that the fix is now mainstream, we decided to drop that mitigation machinery in favor of reducing the complexity. See this [issue](https://github.com/typelevel/cats/issues/1073) for details. + +## Why is some example code not compiling for me? + +A portion of example code requires either the [Kind-projector](https://github.com/non/kind-projector) compiler plugin or partial unification turned on in scalac. The easiest way to turn partial unification on is through this [sbt plugin](https://github.com/fiadliel/sbt-partial-unification). + ## Why can't the compiler find implicit instances for Future? If you have already followed the [imports advice](#what-imports) but are still getting error messages like `could not find implicit value for parameter e: cats.Monad[scala.concurrent.Future]` or `value |+| is not a member of scala.concurrent.Future[Int]`, then make sure that you have an implicit `scala.concurrent.ExecutionContext` in scope. The easiest way to do this is to `import scala.concurrent.ExecutionContext.Implicits.global`, but note that you may want to use a different execution context for your production application. ## How can I turn my List of `` into a `` of a list? -It's really common to have a `List` of values with types like `Option`, `Either`, or `Validated` that you would like to turn "inside out" into an `Option` (or `Either` or `Validated`) of a `List`. The `sequence`, `sequenceU`, `traverse`, and `traverseU` methods are _really_ handy for this. You can read more about them in the [Traverse documentation]({{ site.baseurl }}/typeclasses/traverse.html). +It's really common to have a `List` of values with types like `Option`, `Either`, or `Validated` that you would like to turn "inside out" into an `Option` (or `Either` or `Validated`) of a `List`. The `sequence` and `traverse` methods are _really_ handy for this. You can read more about them in the [Traverse documentation]({{ site.baseurl }}/typeclasses/traverse.html). ## Where is ListT? diff --git a/docs/src/main/tut/typeclasses/functor.md b/docs/src/main/tut/typeclasses/functor.md index 527a28c843..ff0297be1d 100644 --- a/docs/src/main/tut/typeclasses/functor.md +++ b/docs/src/main/tut/typeclasses/functor.md @@ -106,7 +106,7 @@ nested.map(_ + 1) ``` The `Nested` approach, being a distinct type from its constituents, will resolve the usual way modulo -possible [SI-2712][si2712] issues, but requires syntactic and runtime overhead from wrapping and +possible [SI-F2712][si2712] issues, but requires syntactic and runtime overhead from wrapping and unwrapping. [si2712]: https://issues.scala-lang.org/browse/SI-2712 "SI-2712: implement higher-order unification for type constructor inference" diff --git a/free/src/main/scala/cats/free/FreeT.scala b/free/src/main/scala/cats/free/FreeT.scala index 9ee24ba702..99c589f9b8 100644 --- a/free/src/main/scala/cats/free/FreeT.scala +++ b/free/src/main/scala/cats/free/FreeT.scala @@ -164,10 +164,6 @@ object FreeT extends FreeTInstances { def liftT[S[_], M[_], A](value: M[A])(implicit M: Functor[M]): FreeT[S, M, A] = Suspend(M.map(value)(Right(_))) - /** A version of `liftT` that infers the nested type constructor. */ - def liftTU[S[_], MA](value: MA)(implicit M: Unapply[Functor, MA]): FreeT[S, M.M, M.A] = - liftT[S, M.M, M.A](M.subst(value))(M.TC) - /** Suspends a value within a functor in a single step. Monadic unit for a higher-order monad. */ def liftF[S[_], M[_], A](value: S[A])(implicit M: Applicative[M]): FreeT[S, M, A] = Suspend(M.pure(Left(value))) diff --git a/free/src/test/scala/cats/free/FreeTTests.scala b/free/src/test/scala/cats/free/FreeTTests.scala index c7eff2c26f..7beeb92a6b 100644 --- a/free/src/test/scala/cats/free/FreeTTests.scala +++ b/free/src/test/scala/cats/free/FreeTTests.scala @@ -141,11 +141,6 @@ class FreeTTests extends CatsSuite { result.toString.length should be > 0 } - private[free] def liftTUCompilationTests() = { - val a: Either[String, Int]= Right(42) - val b: FreeT[Option, Either[String, ?], Int] = FreeT.liftTU(a) - } - } object FreeTTests extends FreeTTestsInstances { @@ -153,7 +148,6 @@ object FreeTTests extends FreeTTestsInstances { import Arbitrary._ import org.scalacheck.Arbitrary - implicit def freeTIntStateArb[A: Arbitrary]: Arbitrary[FreeTState[A]] = freeTArb[IntState, IntState, A] implicit def freeTArb[F[_], G[_]: Applicative, A](implicit F: Arbitrary[F[A]], G: Arbitrary[G[A]], A: Arbitrary[A]): Arbitrary[FreeT[F, G, A]] = Arbitrary(freeTGen[F, G, A](4)) diff --git a/project/plugins.sbt b/project/plugins.sbt index 265c059fc6..35d86e7288 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -12,3 +12,4 @@ addSbtPlugin("com.github.tkawachi" % "sbt-doctest" % "0.4.1") addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "1.1") addSbtPlugin("com.fortysevendeg" % "sbt-microsites" % "0.3.2") addSbtPlugin("com.dwijnand" % "sbt-travisci" % "1.0.0-M4") +addSbtPlugin("org.lyranthe.sbt" % "partial-unification" % "1.0.0") diff --git a/tests/src/test/scala/cats/tests/KleisliTests.scala b/tests/src/test/scala/cats/tests/KleisliTests.scala index 61768b9dee..af1d15d6e6 100644 --- a/tests/src/test/scala/cats/tests/KleisliTests.scala +++ b/tests/src/test/scala/cats/tests/KleisliTests.scala @@ -210,10 +210,7 @@ class KleisliTests extends CatsSuite { FlatMap[IntReader] Semigroup[IntReader[String]] - // ApplicativeError and MonadError (some SI-2712 workarounds are needed) - type UnitValidated[A] = cats.data.Validated[Unit, A] - type KleisliUV[A] = Kleisli[UnitValidated, Int, A] - ApplicativeError[KleisliUV, Unit] + ApplicativeError[Kleisli[cats.data.Validated[Unit, ?], Int, ?], Unit] ApplicativeError[Kleisli[Option, Int, ?], Unit] MonadError[Kleisli[Option, Int, ?], Unit] } diff --git a/tests/src/test/scala/cats/tests/MonadTest.scala b/tests/src/test/scala/cats/tests/MonadTest.scala index 0df78f6688..8b8935a497 100644 --- a/tests/src/test/scala/cats/tests/MonadTest.scala +++ b/tests/src/test/scala/cats/tests/MonadTest.scala @@ -8,10 +8,8 @@ class MonadTest extends CatsSuite { implicit val testInstance: MonadState[StateT[Id, Int, ?], Int] = StateT.catsDataMonadStateForStateT[Id, Int] import testInstance._ - type StateIdInt[T] = StateT[Id, Int, T] //workaround for SI-2712 - - val increment: StateIdInt[Unit] = modify(_ + 1) - val incrementAndGet: StateIdInt[Int] = increment >> get + val increment: StateT[Id, Int, Unit] = modify(_ + 1) + val incrementAndGet: StateT[Id, Int, Int] = increment >> get test("whileM_") { forAll(Gen.posNum[Int]) { (max: Int) => diff --git a/tests/src/test/scala/cats/tests/NestedTests.scala b/tests/src/test/scala/cats/tests/NestedTests.scala index fc108bffe1..6f70f69fdb 100644 --- a/tests/src/test/scala/cats/tests/NestedTests.scala +++ b/tests/src/test/scala/cats/tests/NestedTests.scala @@ -1,6 +1,7 @@ package cats package tests +import cats.Functor import cats.data._ import cats.functor._ import cats.laws.discipline._ @@ -15,11 +16,6 @@ class NestedTests extends CatsSuite { implicit override val generatorDrivenConfig: PropertyCheckConfiguration = PropertyCheckConfiguration(minSuccessful = 20, sizeRange = 5) - implicit val iso = { - implicit val instance = ListWrapper.functor - invariant[Nested[List, ListWrapper, ?]] - } - { // Invariant composition implicit val instance = ListWrapper.invariant @@ -76,12 +72,8 @@ class NestedTests extends CatsSuite { { // Contravariant + Contravariant = Functor type ConstInt[A] = Const[Int, A] - // SI-2712 - implicit val instance = Nested.catsDataContravariantForNested[ConstInt, Show] - implicit val arbitrary = catsLawsArbitraryForNested[ConstInt, Show, Int] - implicit val eqv = Nested.catsDataEqForNested[ConstInt, Show, Int] checkAll("Nested[Const[Int, ?], Show, ?]", FunctorTests[Nested[ConstInt, Show, ?]].functor[Int, Int, Int]) - checkAll("Functor[Nested[Const[Int, ?], Show, ?]]", SerializableTests.serializable(instance)) + checkAll("Functor[Nested[Const[Int, ?], Show, ?]]", SerializableTests.serializable(Functor[Nested[ConstInt, Show, ?]])) } { diff --git a/tests/src/test/scala/cats/tests/OptionTTests.scala b/tests/src/test/scala/cats/tests/OptionTTests.scala index 041d72d0e0..16d26315aa 100644 --- a/tests/src/test/scala/cats/tests/OptionTTests.scala +++ b/tests/src/test/scala/cats/tests/OptionTTests.scala @@ -1,7 +1,7 @@ package cats package tests -import cats.data.{EitherT, OptionT} +import cats.data.OptionT import cats.kernel.laws.{GroupLaws, OrderLaws} import cats.laws.discipline._ import cats.laws.discipline.arbitrary._ @@ -72,19 +72,6 @@ class OptionTTests extends CatsSuite { implicit val monadError = OptionT.catsDataMonadErrorForOptionT[SEither, String] - import org.scalacheck.Arbitrary - implicit val arb1 = implicitly[Arbitrary[OptionT[SEither, Int]]] - implicit val arb2 = implicitly[Arbitrary[OptionT[SEither, Int => Int]]] - - implicit val eq0 = OptionT.catsDataEqForOptionT[SEither, Option[Int]] - implicit val eq1 = OptionT.catsDataEqForOptionT[SEither, Int] - implicit val eq2 = OptionT.catsDataEqForOptionT[SEither, Unit] - implicit val eq3 = OptionT.catsDataEqForOptionT[SEither, SEither[Unit]] - implicit val eq4 = OptionT.catsDataEqForOptionT[SEither, SEither[Int]] - implicit val eq5 = EitherT.catsDataEqForEitherT[OptionT[SEither, ?], String, Int] - implicit val eq6 = OptionT.catsDataEqForOptionT[SEither, (Int, Int, Int)] - - implicit val iso = CartesianTests.Isomorphisms.invariant[OptionT[SEither, ?]] checkAll("OptionT[Either[String, ?], Int]", MonadErrorTests[OptionT[SEither, ?], String].monadError[Int, Int, Int]) checkAll("MonadError[OptionT[Either[String, ?], ?]]", SerializableTests.serializable(monadError)) diff --git a/tests/src/test/scala/cats/tests/RegressionTests.scala b/tests/src/test/scala/cats/tests/RegressionTests.scala index 50f000c87a..e1a7b5620b 100644 --- a/tests/src/test/scala/cats/tests/RegressionTests.scala +++ b/tests/src/test/scala/cats/tests/RegressionTests.scala @@ -85,7 +85,7 @@ class RegressionTests extends CatsSuite { test("#500: foldMap - traverse consistency") { assert( - List(1,2,3).traverseU(i => Const(List(i))).getConst == List(1,2,3).foldMap(List(_)) + List(1,2,3).traverse(i => Const(List(i))).getConst == List(1,2,3).foldMap(List(_)) ) } @@ -101,31 +101,31 @@ class RegressionTests extends CatsSuite { count = 0 } - List(1,2,6,8).traverseU(validate) should === (Either.left("6 is greater than 5")) + List(1,2,6,8).traverse(validate) should === (Either.left("6 is greater than 5")) // shouldn't have ever evaluted validate(8) checkAndResetCount(3) - Stream(1,2,6,8).traverseU(validate) should === (Either.left("6 is greater than 5")) + Stream(1,2,6,8).traverse(validate) should === (Either.left("6 is greater than 5")) checkAndResetCount(3) type StringMap[A] = Map[String, A] val intMap: StringMap[Int] = Map("one" -> 1, "two" -> 2, "six" -> 6, "eight" -> 8) - intMap.traverseU(validate) should === (Either.left("6 is greater than 5")) + intMap.traverse(validate) should === (Either.left("6 is greater than 5")) checkAndResetCount(3) - NonEmptyList.of(1,2,6,8).traverseU(validate) should === (Either.left("6 is greater than 5")) + NonEmptyList.of(1,2,6,8).traverse(validate) should === (Either.left("6 is greater than 5")) checkAndResetCount(3) - NonEmptyList.of(6,8).traverseU(validate) should === (Either.left("6 is greater than 5")) + NonEmptyList.of(6,8).traverse(validate) should === (Either.left("6 is greater than 5")) checkAndResetCount(1) - List(1,2,6,8).traverseU_(validate) should === (Either.left("6 is greater than 5")) + List(1,2,6,8).traverse_(validate) should === (Either.left("6 is greater than 5")) checkAndResetCount(3) - NonEmptyList.of(1,2,6,7,8).traverseU_(validate) should === (Either.left("6 is greater than 5")) + NonEmptyList.of(1,2,6,7,8).traverse_(validate) should === (Either.left("6 is greater than 5")) checkAndResetCount(3) - NonEmptyList.of(6,7,8).traverseU_(validate) should === (Either.left("6 is greater than 5")) + NonEmptyList.of(6,7,8).traverse_(validate) should === (Either.left("6 is greater than 5")) checkAndResetCount(1) } } diff --git a/tests/src/test/scala/cats/tests/StateTTests.scala b/tests/src/test/scala/cats/tests/StateTTests.scala index 28bb8f2403..dd7c7bd266 100644 --- a/tests/src/test/scala/cats/tests/StateTTests.scala +++ b/tests/src/test/scala/cats/tests/StateTTests.scala @@ -17,7 +17,7 @@ class StateTTests extends CatsSuite { test("traversing state is stack-safe"){ val ns = (0 to 100000).toList - val x = ns.traverseU(_ => add1) + val x = ns.traverse(_ => add1) x.runS(0).value should === (100001) } diff --git a/tests/src/test/scala/cats/tests/UnapplyTests.scala b/tests/src/test/scala/cats/tests/UnapplyTests.scala index 623dbd3381..9044fbfdc4 100644 --- a/tests/src/test/scala/cats/tests/UnapplyTests.scala +++ b/tests/src/test/scala/cats/tests/UnapplyTests.scala @@ -8,24 +8,26 @@ import cats.laws.discipline.SerializableTests // important is that this stuff compiles at all. class UnapplyTests extends CatsSuite { - test("Unapply works for stuff already the right kind") { - val x = Traverse[List].traverseU(List(1,2,3))(Option(_)) - x should === (Some(List(1,2,3))) + + test("Unapply works for F[_] ") { + + val u = implicitly[Unapply.Aux1[Functor, Option[Int], Option, Int]] + + u.TC.map(u.subst(Option(1)))(_ + 1) should ===(Option(2)) } - test("Unapply works for F[_,_] with the left fixed") { - val x = Traverse[List].traverseU(List(1,2,3))(Either.right(_)) - (x: Either[String, List[Int]]) should === (Either.right(List(1,2,3))) + test("Unapply works for F[_, _] with left fixed ") { + + val u = implicitly[Unapply.Aux1[Functor, Either[String, Int], Either[String, ?], Int]] + + u.TC.map(u.subst(1.asRight[String]))(_ + 1) should ===(2.asRight[String]) } test("Unapply works for F[_[_],_] with the left fixed") { - val x: OptionT[List, Int] = OptionT(List(Option(1), Option(2))) - val y: OptionT[List, Int] = OptionT(List(Option(3), Option(4))) - val z: List[Option[(Int,Int)]] = (x |@| y).tupled.value + val u = implicitly[Unapply.Aux1[Functor, OptionT[List, Int], OptionT[List, ?], Int]] - z should be (List(Option((1,3)), Option((1,4)), - Option((2,3)), Option((2,4)))) + u.TC.map(u.subst(OptionT(List(Option(1)))))(_ + 1) should ===(OptionT(List(Option(2)))) } checkAll("Unapply[Functor, Option[String]]", SerializableTests.serializable(Unapply[Functor, Option[String]])) @@ -34,6 +36,8 @@ class UnapplyTests extends CatsSuite { val x: List[Option[Int]] = List(Option(1), Option(2)) val y: Nested[List, Option, Int] = Nested(x) - y.map(_ + 1).value should === (x.map(_.map(_ + 1))) + val u = implicitly[Unapply.Aux1[Functor, Nested[List, Option, Int], Nested[List, Option, ?], Int]] + + u.TC.map(u.subst(y))(_ + 1).value should ===(x.map(_.map(_ + 1))) } } diff --git a/tests/src/test/scala/cats/tests/WordCountTest.scala b/tests/src/test/scala/cats/tests/WordCountTest.scala index 131b70cadd..065f0eaee1 100644 --- a/tests/src/test/scala/cats/tests/WordCountTest.scala +++ b/tests/src/test/scala/cats/tests/WordCountTest.scala @@ -2,7 +2,7 @@ package cats package tests import cats.data.{ Func, AppFunc, Const } -import Func.{ appFunc, appFuncU } +import Func.appFunc /* * This an example of applicative function composition. @@ -29,7 +29,7 @@ class WordCountTest extends CatsSuite { // To count words, we need to detect transitions from whitespace to non-whitespace. val countWord = - appFuncU { (c: Char) => + appFunc { (c: Char) => for { x <- get[Boolean] y = !isSpace(c) diff --git a/tests/src/test/scala/cats/tests/WriterTTests.scala b/tests/src/test/scala/cats/tests/WriterTTests.scala index 69a261c1d9..ccea93c7fe 100644 --- a/tests/src/test/scala/cats/tests/WriterTTests.scala +++ b/tests/src/test/scala/cats/tests/WriterTTests.scala @@ -6,7 +6,6 @@ import cats.functor.{Bifunctor, Contravariant} import cats.laws.discipline._ import cats.laws.discipline.arbitrary._ import cats.laws.discipline.eq._ -import org.scalacheck.Arbitrary import cats.kernel.laws.OrderLaws @@ -358,8 +357,6 @@ class WriterTTests extends CatsSuite { WriterT.catsDataEqForWriterT[Validated[String, ?], ListWrapper[Int], A] implicit val eq2: Eq[EitherT[WriterT[Validated[String, ?], ListWrapper[Int], ?], String, Int]] = EitherT.catsDataEqForEitherT[WriterT[Validated[String, ?], ListWrapper[Int], ?], String, Int] - implicit def arb0[A:Arbitrary]: Arbitrary[WriterT[Validated[String, ?], ListWrapper[Int], A]] = - arbitrary.catsLawsArbitraryForWriterT[Validated[String, ?], ListWrapper[Int], A] Functor[WriterT[Validated[String, ?], ListWrapper[Int], ?]] Apply[WriterT[Validated[String, ?], ListWrapper[Int], ?]] From 1fb29b009f6e5ef0826fcd681b1e53299de67c81 Mon Sep 17 00:00:00 2001 From: "Kai(luo) Wang" Date: Sat, 15 Apr 2017 07:58:43 -0400 Subject: [PATCH 2/5] Update functor.md --- docs/src/main/tut/typeclasses/functor.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/src/main/tut/typeclasses/functor.md b/docs/src/main/tut/typeclasses/functor.md index ff0297be1d..11b2459785 100644 --- a/docs/src/main/tut/typeclasses/functor.md +++ b/docs/src/main/tut/typeclasses/functor.md @@ -106,7 +106,8 @@ nested.map(_ + 1) ``` The `Nested` approach, being a distinct type from its constituents, will resolve the usual way modulo -possible [SI-F2712][si2712] issues, but requires syntactic and runtime overhead from wrapping and -unwrapping. +possible [SI-2712][si2712] issues (which can be addressed through [partial unification][partial-unification]), +but requires syntactic and runtime overhead from wrapping and unwrapping. +[partial-unification]: https://github.com/fiadliel/sbt-partial-unification "A sbt plugin for enabling partial unification" [si2712]: https://issues.scala-lang.org/browse/SI-2712 "SI-2712: implement higher-order unification for type constructor inference" From 537c0a34e2f8dfa0547b1a50dc661658adaca591 Mon Sep 17 00:00:00 2001 From: Kailuo Wang Date: Mon, 17 Apr 2017 10:42:44 -0400 Subject: [PATCH 3/5] addressed misc feedback --- core/src/main/scala/cats/data/Const.scala | 24 +++++++++++++++---- .../src/test/scala/cats/free/FreeTTests.scala | 5 ++++ .../scala/cats/tests/RegressionTests.scala | 2 +- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/core/src/main/scala/cats/data/Const.scala b/core/src/main/scala/cats/data/Const.scala index a6e5646c7b..1af3256095 100644 --- a/core/src/main/scala/cats/data/Const.scala +++ b/core/src/main/scala/cats/data/Const.scala @@ -8,14 +8,14 @@ import cats.functor.Contravariant * [[Const]] can be seen as a type level version of `Function.const[A, B]: A => B => A` * B is set covariant to help type inference. */ -final case class Const[A, +B](getConst: A) { +final case class Const[A, B](getConst: A) { /** * changes the type of the second type parameter */ def retag[C]: Const[A, C] = this.asInstanceOf[Const[A, C]] - def combine[BB >: B](that: Const[A, BB])(implicit A: Semigroup[A]): Const[A, BB] = + def combine(that: Const[A, B])(implicit A: Semigroup[A]): Const[A, B] = Const(A.combine(getConst, that.getConst)) def traverseFilter[F[_], C](f: B => F[Option[C]])(implicit F: Applicative[F]): F[Const[A, C]] = @@ -24,13 +24,13 @@ final case class Const[A, +B](getConst: A) { def traverse[F[_], C](f: B => F[C])(implicit F: Applicative[F]): F[Const[A, C]] = F.pure(retag[C]) - def ===[BB >: B](that: Const[A, BB])(implicit A: Eq[A]): Boolean = + def ===(that: Const[A, B])(implicit A: Eq[A]): Boolean = A.eqv(getConst, that.getConst) - def partialCompare[BB >: B](that: Const[A, BB])(implicit A: PartialOrder[A]): Double = + def partialCompare(that: Const[A, B])(implicit A: PartialOrder[A]): Double = A.partialCompare(getConst, that.getConst) - def compare[BB >: B](that: Const[A, BB])(implicit A: Order[A]): Int = + def compare(that: Const[A, B])(implicit A: Order[A]): Int = A.compare(getConst, that.getConst) def show(implicit A: Show[A]): String = @@ -40,6 +40,20 @@ final case class Const[A, +B](getConst: A) { object Const extends ConstInstances { def empty[A, B](implicit A: Monoid[A]): Const[A, B] = Const(A.empty) + + final class OfPartiallyApplied[B] { + def apply[A](a: A): Const[A, B] = Const(a) + } + + /** + * Convenient syntax for creating a Const[A, B] from an `A` + * {{{ + * scala> import cats.data._ + * scala> Const.of[Int]("a") + * res0: Const[String, Int] = Const(a) + * }}} + */ + def of[B]: OfPartiallyApplied[B] = new OfPartiallyApplied } private[data] sealed abstract class ConstInstances extends ConstInstances0 { diff --git a/free/src/test/scala/cats/free/FreeTTests.scala b/free/src/test/scala/cats/free/FreeTTests.scala index 7beeb92a6b..4457c0141e 100644 --- a/free/src/test/scala/cats/free/FreeTTests.scala +++ b/free/src/test/scala/cats/free/FreeTTests.scala @@ -141,6 +141,11 @@ class FreeTTests extends CatsSuite { result.toString.length should be > 0 } + private[free] def liftTCompilationTests() = { + val a: Either[String, Int]= Right(42) + val b: FreeT[Option, Either[String, ?], Int] = FreeT.liftT(a) + } + } object FreeTTests extends FreeTTestsInstances { diff --git a/tests/src/test/scala/cats/tests/RegressionTests.scala b/tests/src/test/scala/cats/tests/RegressionTests.scala index e1a7b5620b..cacd06504e 100644 --- a/tests/src/test/scala/cats/tests/RegressionTests.scala +++ b/tests/src/test/scala/cats/tests/RegressionTests.scala @@ -85,7 +85,7 @@ class RegressionTests extends CatsSuite { test("#500: foldMap - traverse consistency") { assert( - List(1,2,3).traverse(i => Const(List(i))).getConst == List(1,2,3).foldMap(List(_)) + List(1,2,3).traverse(i => Const.of[List[Int]](List(i))).getConst == List(1,2,3).foldMap(List(_)) ) } From 02daee89632bfa4626a3c3a55fc18fec02ea1a92 Mon Sep 17 00:00:00 2001 From: "Kai(luo) Wang" Date: Thu, 20 Apr 2017 11:21:29 -0400 Subject: [PATCH 4/5] removed the incorrect doc --- core/src/main/scala/cats/data/Const.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/scala/cats/data/Const.scala b/core/src/main/scala/cats/data/Const.scala index 1af3256095..6d862eafe2 100644 --- a/core/src/main/scala/cats/data/Const.scala +++ b/core/src/main/scala/cats/data/Const.scala @@ -6,7 +6,6 @@ import cats.functor.Contravariant /** * [[Const]] is a phantom type, it does not contain a value of its second type parameter `B` * [[Const]] can be seen as a type level version of `Function.const[A, B]: A => B => A` - * B is set covariant to help type inference. */ final case class Const[A, B](getConst: A) { /** From df8aaab1719c72da43d39d96270fcc76e5a0bedb Mon Sep 17 00:00:00 2001 From: "Kai(luo) Wang" Date: Thu, 20 Apr 2017 17:14:33 -0400 Subject: [PATCH 5/5] Update faq.md --- docs/src/main/tut/faq.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/main/tut/faq.md b/docs/src/main/tut/faq.md index cd71bb292d..3cc2626efe 100644 --- a/docs/src/main/tut/faq.md +++ b/docs/src/main/tut/faq.md @@ -11,7 +11,7 @@ position: 4 * [What imports do I need?](#what-imports) * [Where is right-biased `Either`?](#either) - * [Why is the compiler having trouble with types with more than one type parameters?](#si-2712) + * [Why is the compiler having trouble with types with more than one type parameter?](#si-2712) * [Why can't the compiler find implicit instances for Future?](#future-instances) * [Why is some example code not compiling for me?](#example-compile) * [How can I turn my List of `` into a `` of a list?](#traverse) @@ -49,7 +49,7 @@ There are a few minor mismatches between `Xor` and `Either`. For example, in som Similarly, `cats.data.XorT` has been replaced with `cats.data.EitherT`, although since this is a type defined in Cats, you don't need to import syntax or instances for it (although you may need imports for the underlying monad). -## Why is the compiler having trouble with types with more than one type parameters? +## Why is the compiler having trouble with types with more than one type parameter? When you encounter a situation where the same code works fine with a type with one type parameter, e.g. List[A], but doesn't work with types with more than one, e.g. Either[A, B], you probably hit [SI-2712](https://issues.scala-lang.org/browse/SI-2712). Without going into the details, it's highly recommended to enable a partial SI-2712 fix in your project. The easiest way to achieve that is through this [sbt plugin](https://github.com/fiadliel/sbt-partial-unification). Cats used to provide mitigation to this issue semi-transparently, but given the fact that the fix is now mainstream, we decided to drop that mitigation machinery in favor of reducing the complexity. See this [issue](https://github.com/typelevel/cats/issues/1073) for details.