From 57d881974c0f2d4695749385e7603221bbf2c7bb Mon Sep 17 00:00:00 2001 From: wedens Date: Sat, 22 Apr 2017 12:40:34 +0700 Subject: [PATCH 1/5] TransLift replaced with MonadTrans --- core/src/main/scala/cats/MonadTrans.scala | 16 ++++++++ core/src/main/scala/cats/TransLift.scala | 27 ------------- core/src/main/scala/cats/data/EitherT.scala | 8 ++-- core/src/main/scala/cats/data/Kleisli.scala | 8 ++-- core/src/main/scala/cats/data/OptionT.scala | 8 ++-- core/src/main/scala/cats/data/StateT.scala | 12 +++--- core/src/main/scala/cats/data/WriterT.scala | 8 ++-- core/src/main/scala/cats/syntax/all.scala | 2 +- .../main/scala/cats/syntax/monadTrans.scala | 11 ++++++ core/src/main/scala/cats/syntax/package.scala | 2 +- .../main/scala/cats/syntax/transLift.scala | 35 ----------------- free/src/main/scala/cats/free/FreeT.scala | 9 ++--- .../src/test/scala/cats/free/FreeTTests.scala | 9 ++--- .../main/scala/cats/laws/MonadTransLaws.scala | 17 +++++++++ .../laws/discipline/MonadTransTests.scala | 36 ++++++++++++++++++ .../test/scala/cats/tests/EitherTTests.scala | 2 + .../test/scala/cats/tests/KleisliTests.scala | 3 ++ .../test/scala/cats/tests/OptionTTests.scala | 3 ++ .../test/scala/cats/tests/StateTTests.scala | 3 ++ .../scala/cats/tests/TransLiftTests.scala | 38 ------------------- .../test/scala/cats/tests/WriterTTests.scala | 3 ++ 21 files changed, 120 insertions(+), 140 deletions(-) create mode 100644 core/src/main/scala/cats/MonadTrans.scala delete mode 100644 core/src/main/scala/cats/TransLift.scala create mode 100644 core/src/main/scala/cats/syntax/monadTrans.scala delete mode 100644 core/src/main/scala/cats/syntax/transLift.scala create mode 100644 laws/src/main/scala/cats/laws/MonadTransLaws.scala create mode 100644 laws/src/main/scala/cats/laws/discipline/MonadTransTests.scala delete mode 100644 tests/src/test/scala/cats/tests/TransLiftTests.scala diff --git a/core/src/main/scala/cats/MonadTrans.scala b/core/src/main/scala/cats/MonadTrans.scala new file mode 100644 index 0000000000..ab6a8231a4 --- /dev/null +++ b/core/src/main/scala/cats/MonadTrans.scala @@ -0,0 +1,16 @@ +package cats + +/** + * A type class which abstracts over the ability to lift an M[A] into a + * MonadTransformer + */ +trait MonadTrans[MT[_[_], _]] { + /** + * Lift a value of type M[A] into a monad transformer MT[M, A] + */ + def liftT[M[_]: Monad, A](ma: M[A]): MT[M, A] +} + +object MonadTrans { + def apply[MT[_[_], _]](implicit MT: MonadTrans[MT]): MonadTrans[MT] = MT +} diff --git a/core/src/main/scala/cats/TransLift.scala b/core/src/main/scala/cats/TransLift.scala deleted file mode 100644 index 00d734317c..0000000000 --- a/core/src/main/scala/cats/TransLift.scala +++ /dev/null @@ -1,27 +0,0 @@ -package cats - -/** - * A type class which abstracts over the ability to lift an M[A] into a - * MonadTransformer - */ -trait TransLift[MT[_[_], _]] { - - /** - * The type class which constrains liftT as a function of the type - * constructor it is given. A safe "identity" value for this type - * if your transformer does not constrain its lifted effects would - * be `type TC[M[_]] = Trivial`. A more common constraint might be - * `type TC[M[_]] = Monad[M]`. - */ - type TC[M[_]] - - /** - * Lift a value of type M[A] into a monad transformer MT[M, A] - */ - def liftT[M[_]: TC, A](ma: M[A]): MT[M, A] -} - -object TransLift { - type Aux[MT[_[_], _], TC0[_[_]]] = TransLift[MT] { type TC[M[_]] = TC0[M] } - type AuxId[MT[_[_], _]] = Aux[MT, Trivial.PH1] -} diff --git a/core/src/main/scala/cats/data/EitherT.scala b/core/src/main/scala/cats/data/EitherT.scala index b292db8b2a..2bc88aa578 100644 --- a/core/src/main/scala/cats/data/EitherT.scala +++ b/core/src/main/scala/cats/data/EitherT.scala @@ -342,11 +342,9 @@ private[data] abstract class EitherTInstances extends EitherTInstances1 { val F0: Traverse[F] = F } - implicit def catsDataTransLiftForEitherT[E]: TransLift.Aux[EitherT[?[_], E, ?], Functor] = - new TransLift[EitherT[?[_], E, ?]] { - type TC[M[_]] = Functor[M] - - def liftT[M[_]: Functor, A](ma: M[A]): EitherT[M, E, A] = + implicit def catsDataMonadTransForEitherT[E]: MonadTrans[EitherT[?[_], E, ?]] = + new MonadTrans[EitherT[?[_], E, ?]] { + def liftT[M[_]: Monad, A](ma: M[A]): EitherT[M, E, A] = EitherT.liftT(ma) } diff --git a/core/src/main/scala/cats/data/Kleisli.scala b/core/src/main/scala/cats/data/Kleisli.scala index f6480d2332..d0579c9fac 100644 --- a/core/src/main/scala/cats/data/Kleisli.scala +++ b/core/src/main/scala/cats/data/Kleisli.scala @@ -106,11 +106,9 @@ private[data] sealed abstract class KleisliInstances extends KleisliInstances0 { fa.local(f) } - implicit def catsDataTransLiftForKleisli[A]: TransLift.AuxId[Kleisli[?[_], A, ?]] = - new TransLift[Kleisli[?[_], A, ?]] { - type TC[M[_]] = Trivial - - def liftT[M[_], B](ma: M[B])(implicit ev: Trivial): Kleisli[M, A, B] = Kleisli.lift(ma) + implicit def catsDataMonadTransForKleisli[A]: MonadTrans[Kleisli[?[_], A, ?]] = + new MonadTrans[Kleisli[?[_], A, ?]] { + def liftT[M[_]: Monad, B](ma: M[B]): Kleisli[M, A, B] = Kleisli.lift(ma) } implicit def catsDataApplicativeErrorForKleisli[F[_], A, E](implicit AE: ApplicativeError[F, E]): ApplicativeError[Kleisli[F, A, ?], E] = diff --git a/core/src/main/scala/cats/data/OptionT.scala b/core/src/main/scala/cats/data/OptionT.scala index 2396ec21ab..fa4395017b 100644 --- a/core/src/main/scala/cats/data/OptionT.scala +++ b/core/src/main/scala/cats/data/OptionT.scala @@ -208,11 +208,9 @@ private[data] sealed trait OptionTInstances0 extends OptionTInstances1 { private[data] sealed trait OptionTInstances1 extends OptionTInstances2 { // do NOT change this to val! I know it looks like it should work, and really I agree, but it doesn't (for... reasons) - implicit def catsDataTransLiftForOptionT: TransLift.Aux[OptionT, Functor] = - new TransLift[OptionT] { - type TC[M[_]] = Functor[M] - - def liftT[M[_]: Functor, A](ma: M[A]): OptionT[M, A] = OptionT.liftF(ma) + implicit def catsDataMonadTransForOptionT: MonadTrans[OptionT] = + new MonadTrans[OptionT] { + def liftT[M[_]: Monad, A](ma: M[A]): OptionT[M, A] = OptionT.liftF(ma) } implicit def catsDataMonoidKForOptionT[F[_]](implicit F0: Monad[F]): MonoidK[OptionT[F, ?]] = diff --git a/core/src/main/scala/cats/data/StateT.scala b/core/src/main/scala/cats/data/StateT.scala index 4f8b6f8b0c..7eafa57f72 100644 --- a/core/src/main/scala/cats/data/StateT.scala +++ b/core/src/main/scala/cats/data/StateT.scala @@ -188,8 +188,8 @@ private[data] sealed trait StateTInstances extends StateTInstances1 { implicit def catsDataMonadStateForStateT[F[_], S](implicit F0: Monad[F]): MonadState[StateT[F, S, ?], S] = new StateTMonadState[F, S] { implicit def F = F0 } - implicit def catsDataLiftForStateT[S]: TransLift.Aux[StateT[?[_], S, ?], Applicative] = - new StateTTransLift[S] {} + implicit def catsDataMonadTransForStateT[S]: MonadTrans[StateT[?[_], S, ?]] = + new StateTMonadTrans[S] {} } private[data] sealed trait StateTInstances1 extends StateTInstances2 { @@ -289,10 +289,8 @@ private[data] sealed trait StateTMonadState[F[_], S] extends MonadState[StateT[F def set(s: S): StateT[F, S, Unit] = StateT(_ => F.pure((s, ()))) } -private[data] sealed trait StateTTransLift[S] extends TransLift[StateT[?[_], S, ?]] { - type TC[M[_]] = Applicative[M] - - def liftT[M[_]: Applicative, A](ma: M[A]): StateT[M, S, A] = StateT(s => Applicative[M].map(ma)(s -> _)) +private[data] sealed trait StateTMonadTrans[S] extends MonadTrans[StateT[?[_], S, ?]] { + def liftT[M[_]: Monad, A](ma: M[A]): StateT[M, S, A] = StateT(s => Applicative[M].map(ma)(s -> _)) } private[data] sealed trait StateTSemigroupK[F[_], S] extends SemigroupK[StateT[F, S, ?]] { @@ -303,7 +301,7 @@ private[data] sealed trait StateTSemigroupK[F[_], S] extends SemigroupK[StateT[F StateT(s => G.combineK(x.run(s), y.run(s))) } -private[data] sealed trait StateTMonadCombine[F[_], S] extends MonadCombine[StateT[F, S, ?]] with StateTMonad[F, S] with StateTSemigroupK[F, S] with StateTTransLift[S] { +private[data] sealed trait StateTMonadCombine[F[_], S] extends MonadCombine[StateT[F, S, ?]] with StateTMonad[F, S] with StateTSemigroupK[F, S] with StateTMonadTrans[S] { implicit def F: MonadCombine[F] override def G: MonadCombine[F] = F diff --git a/core/src/main/scala/cats/data/WriterT.scala b/core/src/main/scala/cats/data/WriterT.scala index 24b58ad09c..c3cce1398b 100644 --- a/core/src/main/scala/cats/data/WriterT.scala +++ b/core/src/main/scala/cats/data/WriterT.scala @@ -79,11 +79,9 @@ private[data] sealed abstract class WriterTInstances extends WriterTInstances0 { fab.bimap(f, g) } - implicit def catsDataTransLiftForWriterT[W](implicit W: Monoid[W]): TransLift.Aux[WriterT[?[_], W, ?], Functor] = - new TransLift[WriterT[?[_], W, ?]] { - type TC[M[_]] = Functor[M] - - def liftT[M[_]: Functor, A](ma: M[A]): WriterT[M, W, A] = + implicit def catsDataMonadTransForWriterT[W](implicit W: Monoid[W]): MonadTrans[WriterT[?[_], W, ?]] = + new MonadTrans[WriterT[?[_], W, ?]] { + def liftT[M[_]: Monad, A](ma: M[A]): WriterT[M, W, A] = WriterT(Functor[M].map(ma)((W.empty, _))) } diff --git a/core/src/main/scala/cats/syntax/all.scala b/core/src/main/scala/cats/syntax/all.scala index 6cc6c6e4d4..3ad0ffd59f 100644 --- a/core/src/main/scala/cats/syntax/all.scala +++ b/core/src/main/scala/cats/syntax/all.scala @@ -39,7 +39,7 @@ trait AllSyntax with ShowSyntax with SplitSyntax with StrongSyntax - with TransLiftSyntax + with MonadTransSyntax with TraverseFilterSyntax with TraverseSyntax with TupleSyntax diff --git a/core/src/main/scala/cats/syntax/monadTrans.scala b/core/src/main/scala/cats/syntax/monadTrans.scala new file mode 100644 index 0000000000..11a4ddae39 --- /dev/null +++ b/core/src/main/scala/cats/syntax/monadTrans.scala @@ -0,0 +1,11 @@ +package cats +package syntax + +trait MonadTransSyntax { + implicit final def catsSyntaxMonadTrans[F[_], A](fa: F[A]): MonadTransOps[F, A] = new MonadTransOps(fa) +} + +final class MonadTransOps[F[_], A](val fa: F[A]) extends AnyVal { + def liftT[MT[_[_], _]](implicit F: Monad[F], MT: MonadTrans[MT]): MT[F, A] = + MT.liftT(fa) +} diff --git a/core/src/main/scala/cats/syntax/package.scala b/core/src/main/scala/cats/syntax/package.scala index ed39f39a65..2f1986e5e4 100644 --- a/core/src/main/scala/cats/syntax/package.scala +++ b/core/src/main/scala/cats/syntax/package.scala @@ -39,7 +39,7 @@ package object syntax { object show extends Show.ToShowOps object split extends SplitSyntax object strong extends StrongSyntax - object transLift extends TransLiftSyntax + object monadTrans extends MonadTransSyntax object traverse extends TraverseSyntax object traverseFilter extends TraverseFilterSyntax object tuple extends TupleSyntax diff --git a/core/src/main/scala/cats/syntax/transLift.scala b/core/src/main/scala/cats/syntax/transLift.scala deleted file mode 100644 index 5f3c228c42..0000000000 --- a/core/src/main/scala/cats/syntax/transLift.scala +++ /dev/null @@ -1,35 +0,0 @@ -package cats -package syntax - -trait TransLiftSyntax { - 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 { - import TLExtract._ - - def liftT[MT0[_[_], _]](implicit extract: TLExtract[SingletonMT { type MT[F[_], B] = MT0[F, B] }, SingletonM { type M[B] = M0[B] }]): MT0[M0, A] = extract.TL.liftT(ma)(extract.TC) -} - -trait TLExtract[MTS <: TLExtract.SingletonMT, MS <: TLExtract.SingletonM] { - val TL: TransLift[MTS#MT] - val TC: TL.TC[MS#M] -} - -object TLExtract { - - trait SingletonMT { - type MT[F[_], A] - } - - trait SingletonM { - type M[A] - } - - implicit def extract[MTS <: SingletonMT, MS <: SingletonM, TC[_[_]]](implicit TL0: TransLift.Aux[MTS#MT, TC], TC0: TC[MS#M]): TLExtract[MTS, MS] = new TLExtract[MTS, MS] { - val TL = TL0 - val TC = TC0 - } - - implicit def extractId[MTS <: SingletonMT, MS <: SingletonM](implicit TL0: TransLift.Aux[MTS#MT, Trivial.PH1]): TLExtract[MTS, MS] = extract[MTS, MS, Trivial.PH1] -} diff --git a/free/src/main/scala/cats/free/FreeT.scala b/free/src/main/scala/cats/free/FreeT.scala index 99c589f9b8..5a48e1a6cd 100644 --- a/free/src/main/scala/cats/free/FreeT.scala +++ b/free/src/main/scala/cats/free/FreeT.scala @@ -206,12 +206,9 @@ private[free] sealed trait FreeTInstances1 extends FreeTInstances2 { implicit def M: Applicative[M] = M0 } - implicit def catsFreeTransLiftForFreeT[S[_]]: TransLift.Aux[FreeT[S, ?[_], ?], Functor] = - new TransLift[FreeT[S, ?[_], ?]] { - - type TC[M[_]] = Functor[M] - - override def liftT[M[_]: Functor, A](ma: M[A]): FreeT[S, M, A] = + implicit def catsFreeMonadTransForFreeT[S[_]]: MonadTrans[FreeT[S, ?[_], ?]] = + new MonadTrans[FreeT[S, ?[_], ?]] { + override def liftT[M[_]: Monad, A](ma: M[A]): FreeT[S, M, A] = FreeT.liftT(ma) } } diff --git a/free/src/test/scala/cats/free/FreeTTests.scala b/free/src/test/scala/cats/free/FreeTTests.scala index 8efdeb83c8..1b5808b335 100644 --- a/free/src/test/scala/cats/free/FreeTTests.scala +++ b/free/src/test/scala/cats/free/FreeTTests.scala @@ -50,6 +50,10 @@ class FreeTTests extends CatsSuite { checkAll("MonadState[FreeT[State[Int, ?],State[Int, ?], ?], Int]", SerializableTests.serializable(MonadState[FreeTState, Int])) } + { + checkAll("MonadTrans[FreeT[Option, ?[_], ?]]", MonadTransTests[FreeT[Option, ?[_], ?]].monadTrans[Option, Int, Int]) + } + test("FlatMap stack safety tested with 50k flatMaps") { val expected = Applicative[FreeTOption].pure(()) val result = @@ -96,11 +100,6 @@ class FreeTTests extends CatsSuite { val b = a.hoist(FunctionK.id) } - test("transLift for FreeT requires only Functor") { - implicit val transLiftInstance = FreeT.catsFreeTransLiftForFreeT[JustFunctor] - val d: FreeT[JustFunctor, JustFunctor, Int] = transLiftInstance.liftT[JustFunctor, Int](JustFunctor(1)) - } - test("compile to universal id equivalent to original instance") { forAll { a: FreeTOption[Int] => val b = a.compile(FunctionK.id) diff --git a/laws/src/main/scala/cats/laws/MonadTransLaws.scala b/laws/src/main/scala/cats/laws/MonadTransLaws.scala new file mode 100644 index 0000000000..d361af8438 --- /dev/null +++ b/laws/src/main/scala/cats/laws/MonadTransLaws.scala @@ -0,0 +1,17 @@ +package cats +package laws + +trait MonadTransLaws[MT[_[_], _]] { + implicit def MT: MonadTrans[MT] + + def identity[G[_], A](a: A)(implicit G: Monad[G], MTM: Monad[MT[G, ?]]): IsEq[MT[G, A]] = + MT.liftT(G.pure(a)) <-> MTM.pure(a) + + def composition[G[_], A, B](ga: G[A], f: A => G[B])(implicit G: Monad[G], MTM: Monad[MT[G, ?]]): IsEq[MT[G, B]] = + MT.liftT(G.flatMap(ga)(f)) <-> MTM.flatMap(MT.liftT(ga))(a => MT.liftT(f(a))) +} + +object MonadTransLaws { + def apply[MT[_[_], _]](implicit ev: MonadTrans[MT]): MonadTransLaws[MT] = + new MonadTransLaws[MT] { def MT: MonadTrans[MT] = ev } +} diff --git a/laws/src/main/scala/cats/laws/discipline/MonadTransTests.scala b/laws/src/main/scala/cats/laws/discipline/MonadTransTests.scala new file mode 100644 index 0000000000..c20d124465 --- /dev/null +++ b/laws/src/main/scala/cats/laws/discipline/MonadTransTests.scala @@ -0,0 +1,36 @@ +package cats +package laws +package discipline + +import org.scalacheck.{Arbitrary, Cogen, Prop} +import org.typelevel.discipline.Laws +import Prop._ + +trait MonadTransTests[MT[_[_], _]] extends Laws { + def laws: MonadTransLaws[MT] + + def monadTrans[G[_]: Monad, A: Arbitrary: Eq, B: Eq](implicit + MonadMTG: Monad[MT[G, ?]], + ArbGA: Arbitrary[G[A]], + ArbGB: Arbitrary[G[B]], + CogenA: Cogen[A], + EqGA: Eq[G[A]], + EqGB: Eq[G[B]], + EqMTGA: Eq[MT[G, A]], + EqMTGB: Eq[MT[G, B]] + ): RuleSet = { + new DefaultRuleSet( + name = "monadTrans", + parent = None, + "monadTrans identity" -> forAll(laws.identity[G, A] _), + "monadTrans composition" -> forAll(laws.composition[G, A, B] _) + ) + } +} + +object MonadTransTests { + def apply[MT[_[_], _]: MonadTrans]: MonadTransTests[MT] = + new MonadTransTests[MT] { + def laws: MonadTransLaws[MT] = MonadTransLaws[MT] + } +} diff --git a/tests/src/test/scala/cats/tests/EitherTTests.scala b/tests/src/test/scala/cats/tests/EitherTTests.scala index dbe79220ce..8be07514c6 100644 --- a/tests/src/test/scala/cats/tests/EitherTTests.scala +++ b/tests/src/test/scala/cats/tests/EitherTTests.scala @@ -53,9 +53,11 @@ class EitherTTests extends CatsSuite { Functor[EitherT[ListWrapper, String, ?]] Applicative[EitherT[ListWrapper, String, ?]] Monad[EitherT[ListWrapper, String, ?]] + MonadTrans[EitherT[?[_], String, ?]] checkAll("EitherT[ListWrapper, String, Int]", MonadErrorTests[EitherT[ListWrapper, String, ?], String].monadError[Int, Int, Int]) checkAll("MonadError[EitherT[List, ?, ?]]", SerializableTests.serializable(MonadError[EitherT[ListWrapper, String, ?], String])) + checkAll("MonadTrans[EitherT[?[_], String, ?]]", MonadTransTests[EitherT[?[_], String, ?]].monadTrans[ListWrapper, Int, Int]) } { diff --git a/tests/src/test/scala/cats/tests/KleisliTests.scala b/tests/src/test/scala/cats/tests/KleisliTests.scala index 4fb32452df..546764c033 100644 --- a/tests/src/test/scala/cats/tests/KleisliTests.scala +++ b/tests/src/test/scala/cats/tests/KleisliTests.scala @@ -121,6 +121,7 @@ class KleisliTests extends CatsSuite { checkAll("Kleisli[Option, ?, Int]", ContravariantTests[Kleisli[Option, ?, Int]].contravariant[Int, Int, Int]) checkAll("Contravariant[Kleisli[Option, ?, Int]]", SerializableTests.serializable(Contravariant[Kleisli[Option, ?, Int]])) + checkAll("MonadTrans[Kleisli[?[_], Int, ?]]", MonadTransTests[Kleisli[?[_], Int, ?]].monadTrans[Option, Int, Int]) test("local composes functions") { forAll { (f: Int => Option[String], g: Int => Int, i: Int) => @@ -226,5 +227,7 @@ class KleisliTests extends CatsSuite { ApplicativeError[Kleisli[cats.data.Validated[Unit, ?], Int, ?], Unit] ApplicativeError[Kleisli[Option, Int, ?], Unit] MonadError[Kleisli[Option, Int, ?], Unit] + + MonadTrans[Kleisli[?[_], Int, ?]] } } diff --git a/tests/src/test/scala/cats/tests/OptionTTests.scala b/tests/src/test/scala/cats/tests/OptionTTests.scala index 16d26315aa..88aec2e757 100644 --- a/tests/src/test/scala/cats/tests/OptionTTests.scala +++ b/tests/src/test/scala/cats/tests/OptionTTests.scala @@ -57,6 +57,7 @@ class OptionTTests extends CatsSuite { checkAll("OptionT[ListWrapper, Int]", MonoidKTests[OptionT[ListWrapper, ?]].monoidK[Int]) checkAll("MonoidK[OptionT[ListWrapper, ?]]", SerializableTests.serializable(MonoidK[OptionT[ListWrapper, ?]])) + checkAll("MonadTrans[OptionT]", MonadTransTests[OptionT].monadTrans[ListWrapper, Int, Int]) FlatMap[OptionT[ListWrapper, ?]] Applicative[OptionT[ListWrapper, ?]] @@ -307,6 +308,8 @@ class OptionTTests extends CatsSuite { implicit val T = ListWrapper.traverse implicit val M = ListWrapper.monad Functor[OptionT[ListWrapper, ?]] + + MonadTrans[OptionT] } } diff --git a/tests/src/test/scala/cats/tests/StateTTests.scala b/tests/src/test/scala/cats/tests/StateTTests.scala index 3fcf1edad8..61e4ba61d3 100644 --- a/tests/src/test/scala/cats/tests/StateTTests.scala +++ b/tests/src/test/scala/cats/tests/StateTTests.scala @@ -235,12 +235,15 @@ class StateTTests extends CatsSuite { checkAll("StateT[ListWrapper, Int, Int]", MonadTests[StateT[ListWrapper, Int, ?]].monad[Int, Int, Int]) checkAll("Monad[StateT[ListWrapper, Int, ?]]", SerializableTests.serializable(Monad[StateT[ListWrapper, Int, ?]])) + checkAll("MonadTrans[EitherT[?[_], String, ?]]", MonadTransTests[EitherT[?[_], String, ?]].monadTrans[ListWrapper, Int, Int]) Monad[StateT[ListWrapper, Int, ?]] FlatMap[StateT[ListWrapper, Int, ?]] Applicative[StateT[ListWrapper, Int, ?]] Apply[StateT[ListWrapper, Int, ?]] Functor[StateT[ListWrapper, Int, ?]] + + MonadTrans[StateT[?[_], Int, ?]] } { diff --git a/tests/src/test/scala/cats/tests/TransLiftTests.scala b/tests/src/test/scala/cats/tests/TransLiftTests.scala deleted file mode 100644 index 8a81fa5bdf..0000000000 --- a/tests/src/test/scala/cats/tests/TransLiftTests.scala +++ /dev/null @@ -1,38 +0,0 @@ -package cats -package tests - -import cats.data.{EitherT, OptionT, WriterT, Kleisli, StateT} - -class TransLiftTests extends CatsSuite { - - case class NoTypeclass[A](a: A) - - case class JustFunctor[A](a: A) - - implicit val jfFunctor: Functor[JustFunctor] = new Functor[JustFunctor] { - override def map[A, B](fa: JustFunctor[A])(f: A => B): JustFunctor[B] = JustFunctor(f(fa.a)) - } - - case class JustAp[A](a: A) - - implicit val jfApp: Applicative[JustAp] = new Applicative[JustAp] { - override def pure[A](a: A): JustAp[A] = JustAp(a) - override def ap[A, B](ff: JustAp[A => B])(fa: JustAp[A]): JustAp[B] = JustAp(ff.a(fa.a)) - override def product[A, B](fa: JustAp[A],fb: JustAp[B]): JustAp[(A, B)] = JustAp(fa.a -> fb.a) - override def map[A, B](fa: JustAp[A])(f: A => B): JustAp[B] = JustAp(f(fa.a)) - } - - test("transLift for EitherT, OptionT, WriterT requires only Functor") { - val e: EitherT[JustFunctor, Int, Int] = JustFunctor(1).liftT[λ[(α[_], β) => EitherT[α, Int, β]]] - val c: OptionT[JustFunctor, Int] = JustFunctor(1).liftT[OptionT] - val a: WriterT[JustFunctor, Int, Int] = JustFunctor(1).liftT[λ[(α[_], β) => WriterT[α, Int, β]]] - } - - test("transLift for StateT requires Applicative Functor") { - val f: StateT[JustAp, Int, Int] = JustAp(1).liftT[λ[(α[_], β) => StateT[α, Int, β]]] - } - - test("transLift for Kleisli doesn't require anything of the wrapped value"){ - val e: Kleisli[NoTypeclass, Int, Int] = NoTypeclass(1).liftT[λ[(α[_], β) => Kleisli[α, Int, β]]] - } -} diff --git a/tests/src/test/scala/cats/tests/WriterTTests.scala b/tests/src/test/scala/cats/tests/WriterTTests.scala index ccea93c7fe..bf16d48fbf 100644 --- a/tests/src/test/scala/cats/tests/WriterTTests.scala +++ b/tests/src/test/scala/cats/tests/WriterTTests.scala @@ -257,12 +257,15 @@ class WriterTTests extends CatsSuite { checkAll("WriterT[ListWrapper, ListWrapper[Int], ?]", MonadWriterTests[WriterT[ListWrapper, ListWrapper[Int], ?], ListWrapper[Int]].monadWriter[Int, Int, Int]) checkAll("MonadWriter[WriterT[ListWrapper, ListWrapper[Int], ?], List[String]]", SerializableTests.serializable(MonadWriter[WriterT[ListWrapper, ListWrapper[Int], ?], ListWrapper[Int]])) + checkAll("MonadTrans[WriterT[?[_], ListWrapper[Int], ?]]", MonadTransTests[WriterT[?[_], ListWrapper[Int], ?]].monadTrans[ListWrapper, Int, Int]) + Functor[WriterT[Id, ListWrapper[Int], ?]] Apply[WriterT[Id, ListWrapper[Int], ?]] Applicative[WriterT[Id, ListWrapper[Int], ?]] FlatMap[WriterT[Id, ListWrapper[Int], ?]] CoflatMap[WriterT[Id, ListWrapper[Int], ?]] Monad[WriterT[Id, ListWrapper[Int], ?]] + MonadTrans[WriterT[?[_], ListWrapper[Int], ?]] Functor[Writer[ListWrapper[Int], ?]] Apply[Writer[ListWrapper[Int], ?]] From 00a4fd1c5ca6fa297f419e1ba463672c99311de3 Mon Sep 17 00:00:00 2001 From: wedens Date: Sat, 22 Apr 2017 13:39:47 +0700 Subject: [PATCH 2/5] remove Trivial --- core/src/main/scala/cats/Trivial.scala | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 core/src/main/scala/cats/Trivial.scala diff --git a/core/src/main/scala/cats/Trivial.scala b/core/src/main/scala/cats/Trivial.scala deleted file mode 100644 index 2a8ff9200a..0000000000 --- a/core/src/main/scala/cats/Trivial.scala +++ /dev/null @@ -1,23 +0,0 @@ -package cats - -/** - * The "Unit type class". The only instance of `Trivial` is given by - * `Trivial.manifest`, and this instance is guaranteed to be in the - * implicit scope. Several convenience type aliases are provided in - * companion object, covering a few common use cases and avoiding the - * need for unnecessary lambdas (e.g. if you want a trivial type class - * instance for a type constructor, you should use `Trivial.PH1`). - */ -sealed trait Trivial - -object Trivial { - type P1[A] = Trivial - type PH1[F[_]] = Trivial - type P1H1[F[_], A] = Trivial - type P2[A, B] = Trivial - type P2H1[F[_], A, B] = Trivial - type P3[A, B, C] = Trivial - type P3H1[F[_], A, B, C] = Trivial - - implicit val catsTrivialInstance: Trivial = new Trivial {} -} From 946f17196a32626669f4fe23257d7d7ce7aed608 Mon Sep 17 00:00:00 2001 From: wedens Date: Mon, 24 Apr 2017 13:21:56 +0700 Subject: [PATCH 3/5] MonadTrans syntax test --- tests/src/test/scala/cats/tests/SyntaxTests.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/src/test/scala/cats/tests/SyntaxTests.scala b/tests/src/test/scala/cats/tests/SyntaxTests.scala index 23172cd7bc..ec2a18f8ec 100644 --- a/tests/src/test/scala/cats/tests/SyntaxTests.scala +++ b/tests/src/test/scala/cats/tests/SyntaxTests.scala @@ -244,6 +244,11 @@ object SyntaxTests extends AllInstances with AllSyntax { val fa = a.pure[F] } + def testMonadTrans[MT[_[_], _], M[_], A](implicit MT: MonadTrans[MT], M: Monad[M]): Unit = { + val fa = mock[M[A]] + val mtf = fa.liftT[MT] + } + def testApplicativeError[F[_, _], E, A](implicit F: ApplicativeError[F[E, ?], E]): Unit = { type G[X] = F[E, X] From 35dc00c560f4e4a7b0d731fc73e58bc0deb6de59 Mon Sep 17 00:00:00 2001 From: wedens Date: Mon, 24 Apr 2017 21:17:11 +0700 Subject: [PATCH 4/5] fix doc style --- core/src/main/scala/cats/MonadTrans.scala | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/core/src/main/scala/cats/MonadTrans.scala b/core/src/main/scala/cats/MonadTrans.scala index ab6a8231a4..f70fc10776 100644 --- a/core/src/main/scala/cats/MonadTrans.scala +++ b/core/src/main/scala/cats/MonadTrans.scala @@ -1,13 +1,14 @@ package cats /** - * A type class which abstracts over the ability to lift an M[A] into a - * MonadTransformer - */ + * A type class which abstracts over the ability to lift an M[A] into a + * MonadTransformer + */ trait MonadTrans[MT[_[_], _]] { + /** - * Lift a value of type M[A] into a monad transformer MT[M, A] - */ + * Lift a value of type M[A] into a monad transformer MT[M, A] + */ def liftT[M[_]: Monad, A](ma: M[A]): MT[M, A] } From d39d2f965665d4d9528adf7986c3ec9e54adbc21 Mon Sep 17 00:00:00 2001 From: wedens Date: Fri, 28 Apr 2017 10:46:24 +0700 Subject: [PATCH 5/5] ordered syntax traits --- core/src/main/scala/cats/syntax/all.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/syntax/all.scala b/core/src/main/scala/cats/syntax/all.scala index 3ad0ffd59f..ea8cb90511 100644 --- a/core/src/main/scala/cats/syntax/all.scala +++ b/core/src/main/scala/cats/syntax/all.scala @@ -24,10 +24,11 @@ trait AllSyntax with InvariantSyntax with IorSyntax with ListSyntax - with MonadSyntax with MonadCombineSyntax with MonadErrorSyntax with MonadFilterSyntax + with MonadSyntax + with MonadTransSyntax with MonoidSyntax with OptionSyntax with OrderSyntax @@ -39,7 +40,6 @@ trait AllSyntax with ShowSyntax with SplitSyntax with StrongSyntax - with MonadTransSyntax with TraverseFilterSyntax with TraverseSyntax with TupleSyntax