diff --git a/README.md b/README.md index b5c62b4d..2f3b80b7 100644 --- a/README.md +++ b/README.md @@ -23,22 +23,38 @@ libraryDependencies += "org.typelevel" %% "kittens" % "1.0.0-M11" ### Auto derived Examples + + ```scala -scala> import cats.derived._, functor._, legacy._ -scala> import cats.Functor +scala> import cats.implicit._, cats._ -scala> case class Cat[Food](food: Option[Food], foods: List[Food]) +scala> case class Cat[Food](food: Food, foods: List[Food]) defined class Cat -scala> val f = Functor[Cat] -f: cats.Functor[Cat] = cats.derived.MkFunctor2$$anon$4@782b2ad1 +scala> val cat = Cat(1, List(2, 3)) +cat: Cat[Int] = Cat(1,List(2, 3)) + +``` + +#### Derive `Functor` -scala> val cat = Cat(Some(1), List(2, 3)) -cat: Cat[Int] = Cat(Some(1),List(2, 3)) +```scala +scala> implicit val fc = cats.derive.functor[Cat] +FC: cats.Functor[Cat] = cats.derived.MkFunctor2$$anon$4@1c60573f + +scala> cat.map(_ + 1) +res0: Cat[Int] = Cat(2,List(3, 4)) +``` + +#### Derive `Show` + +```scala +scala> implicit val cs = cats.derive.show[Cat[Int]] +catShow: cats.Show[Cat[Int]] = cats.derived.MkShow3$$anon$1@7ec30e6b -scala> f.map(cat)(_ + 1) -res3: Cat[Int] = Cat(Some(2),List(3, 4)) +scala> cat.show +res1: String = Cat(food = 1, foods = List(2, 3)) ``` ### Sequence examples diff --git a/build.sbt b/build.sbt index 2c15d46c..b4548842 100644 --- a/build.sbt +++ b/build.sbt @@ -5,7 +5,7 @@ import sbt._ lazy val buildSettings = Seq( organization := "org.typelevel", - scalaVersion := "2.12.2", + scalaVersion := "2.12.3", crossScalaVersions := Seq( "2.11.11", scalaVersion.value) ) @@ -26,7 +26,6 @@ lazy val commonSettings = Seq( "org.typelevel" %% "cats-core" % "1.0.0-MF", "org.typelevel" %% "alleycats-core" % "0.2.0", "com.chuusai" %% "shapeless" % "2.3.2", - "org.typelevel" %% "export-hook" % "1.2.0", "org.scalatest" %% "scalatest" % "3.0.3" % "test", "org.scalacheck" %% "scalacheck" % "1.13.5" % "test", "org.typelevel" %% "cats-laws" % "1.0.0-MF" % "test", @@ -54,8 +53,8 @@ lazy val commonJvmSettings = Seq( lazy val coreSettings = buildSettings ++ commonSettings ++ publishSettings ++ releaseSettings lazy val root = project.in(file(".")) - .aggregate(coreJS, coreJVM, extraTests) - .dependsOn(coreJS, coreJVM, extraTests) + .aggregate(coreJS, coreJVM) + .dependsOn(coreJS, coreJVM) .settings(coreSettings:_*) .settings(noPublishSettings) @@ -65,12 +64,6 @@ lazy val core = crossProject.crossType(CrossType.Pure) .jsSettings(commonJsSettings:_*) .jvmSettings(commonJvmSettings:_*) -//Monad and Applicative tests are taking a long time to compile, separating them to another module to help development, and scala 2.10.x build on travis. -lazy val extraTests = project.in(file("extra-tests")) - .settings(moduleName := "kittens-tests") - .dependsOn(coreJVM % "compile->compile;test->test") - .settings(coreSettings:_*) - .settings(noPublishSettings) lazy val coreJVM = core.jvm lazy val coreJS = core.js @@ -103,9 +96,9 @@ lazy val publishSettings = Seq( publishMavenStyle := true, publishArtifact in Test := false, pomIncludeRepository := { _ => false }, - publishTo <<= version { (v: String) => + publishTo := { val nexus = "https://oss.sonatype.org/" - if (v.trim.endsWith("SNAPSHOT")) + if (version.value.trim.endsWith("SNAPSHOT")) Some("snapshots" at nexus + "content/repositories/snapshots") else Some("releases" at nexus + "service/local/staging/deploy/maven2") @@ -141,7 +134,7 @@ lazy val releaseSettings = Seq( publishArtifacts, setNextVersion, commitNextVersion, - ReleaseStep(action = Command.process("sonatypeReleaseAll", _), enableCrossBuild = true), + ReleaseStep(action = Command.process("sonatypeReleaseAll", _)), pushChanges ) ) diff --git a/core/src/main/scala/cats/derive.scala b/core/src/main/scala/cats/derive.scala new file mode 100644 index 00000000..eaa4f3ef --- /dev/null +++ b/core/src/main/scala/cats/derive.scala @@ -0,0 +1,19 @@ +package cats +import alleycats.{EmptyK, Pure} +import cats.derived._ + +object derive { + def functor[F[_]](implicit F: MkFunctor[F]) : Functor[F] = F + def emptyK[F[_]](implicit F: MkEmptyK[F]): EmptyK[F] = F + def eq[T](implicit F: MkEq[T]): Eq[T] = F + def foldable[F[_]](implicit F: MkFoldable[F]): Foldable[F] = F + def monoid[T](implicit T: MkMonoid[T]): Monoid[T] = T + def monoidK[F[_]](implicit F: MkMonoidK[F]): MonoidK[F] = F + def pure[F[_]](implicit F: MkPure[F]): Pure[F] = F + def semigroup[T](implicit F: MkSemigroup[T]): Semigroup[T] = F + def semigroupK[F[_]](implicit F: MkSemigroupK[F]): SemigroupK[F] = F + def show[T](implicit F: MkShow[T]): Show[T] = F + + def iterable[F[_], A](fa: F[A])(implicit mif: MkIterable[F]): Iterable[A] = mif.iterable(fa) + +} diff --git a/core/src/main/scala/cats/derived/applicative.scala b/core/src/main/scala/cats/derived/applicative.scala deleted file mode 100644 index a2ddd80f..00000000 --- a/core/src/main/scala/cats/derived/applicative.scala +++ /dev/null @@ -1,18 +0,0 @@ -package cats.derived - -import alleycats.Pure -import cats.{Apply, Applicative, Foldable, Functor} - -object MkApplicative { - - implicit def mkApplicative[F[_]]( - implicit - P: Pure[F], - A: Apply[F] - ): Applicative[F] = new Applicative[F] { - def pure[A](x: A): F[A] = P.pure(x) - - def ap[A, B](ff: F[(A) => B])(fa: F[A]): F[B] = A.ap(ff)(fa) - } - -} diff --git a/core/src/main/scala/cats/derived/apply.scala b/core/src/main/scala/cats/derived/apply.scala deleted file mode 100644 index 86bdc144..00000000 --- a/core/src/main/scala/cats/derived/apply.scala +++ /dev/null @@ -1,55 +0,0 @@ -package cats.derived - -import cats.{Foldable, Functor, Eval, Apply}, Eval.now -import alleycats.{EmptyK, Pure} -import export.{ exports, imports, reexports } -import shapeless._ - -// todo doesn't work because an implicit Functor needs to be scope while Apply itself implements Functor -//@reexports[MkApply] -//object apply { -// @imports[Apply] -// object legacy -//} - -trait MkApply[F[_]] extends Apply[F] - -@exports -object MkApply extends MkApply0 { - def apply[F[_]](implicit maf: MkApply[F]): MkApply[F] = maf -} - -trait MkApply0 extends MkApply1 { - implicit def mkWithEmptyK[F[_]]( - implicit - F: Cached[Functor[F]], - E: Cached[EmptyK[F]], - Fdb: Cached[Foldable[F]] - ): MkApply[F] = doMkWithEmptyK(E.value, F.value) -} - -trait MkApply1 { - implicit def mkWithoutEmpty[F[_]]( - implicit - F: Cached[Functor[F]], - Fdb: Cached[Foldable[F]] - ): MkApply[F] = { - val nullEmpty = new EmptyK[F] { - def empty[A]: F[A] = null.asInstanceOf[F[A]] - } - doMkWithEmptyK(nullEmpty, F.value) - } - - protected def doMkWithEmptyK[F[_]](E: EmptyK[F], F: Functor[F])( - implicit - Fdb: Cached[Foldable[F]] - ): MkApply[F] = new MkApply[F] { - def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] = { - Fdb.value.foldLeft[A => B, F[B]](ff, E.empty[B])((_, f) => F.map(fa)(f)) - } - - def map[A, B](fa: F[A])(f: A => B): F[B] = F.map(fa)(f) - - } - -} diff --git a/core/src/main/scala/cats/derived/consk.scala b/core/src/main/scala/cats/derived/consk.scala index c1b3bfc0..f57531ad 100644 --- a/core/src/main/scala/cats/derived/consk.scala +++ b/core/src/main/scala/cats/derived/consk.scala @@ -17,19 +17,18 @@ package cats.derived import alleycats.ConsK -import export.ExportGeneric import shapeless._ object consk { object exports { - def apply[F[_]](implicit mcff: MkConsK[F, F]): ExportGeneric[ConsK[F]] = - ExportGeneric[ConsK[F]]( + def apply[F[_]](implicit mcff: MkConsK[F, F]) = + ConsK[F]( new ConsK[F] { def cons[A](hd: A, tl: F[A]): F[A] = mcff.cons(hd, tl) } ) - implicit def deriveConsK[F[_]](implicit mcff: MkConsK[F, F]): ExportGeneric[ConsK[F]] = apply[F] + implicit def deriveConsK[F[_]](implicit mcff: MkConsK[F, F]): ConsK[F] = apply[F] } } diff --git a/core/src/main/scala/cats/derived/empty.scala b/core/src/main/scala/cats/derived/empty.scala index 8420a79c..f4682d14 100644 --- a/core/src/main/scala/cats/derived/empty.scala +++ b/core/src/main/scala/cats/derived/empty.scala @@ -17,32 +17,27 @@ package cats.derived import alleycats.Empty -import export.{ exports, imports, reexports } -import shapeless._ -@reexports[MkEmpty] -object empty { - @imports[Empty] - object legacy -} +import shapeless._ trait MkEmpty[T] extends Empty[T] -@exports -object MkEmpty { +object MkEmpty extends MkEmptyDerivation { def apply[T](implicit e: MkEmpty[T]): MkEmpty[T] = e +} - implicit val hnil: MkEmpty[HNil] = +trait MkEmptyDerivation { + implicit val mkEmptyHnil: MkEmpty[HNil] = new MkEmpty[HNil] { def empty = HNil } - implicit def hcons[H, T <: HList](implicit eh: Lazy[Empty[H]], et: Lazy[MkEmpty[T]]) + implicit def mkEmptyHcons[H, T <: HList](implicit eh: Lazy[Empty[H]], et: Lazy[MkEmpty[T]]) : MkEmpty[H :: T] = new MkEmpty[H :: T] { val empty = eh.value.empty :: et.value.empty } - implicit def generic[T, R](implicit gen: Generic.Aux[T, R], er: Lazy[MkEmpty[R]]) + implicit def mkEmptyGeneric[T, R](implicit gen: Generic.Aux[T, R], er: Lazy[MkEmpty[R]]) : MkEmpty[T] = new MkEmpty[T] { val empty = gen.from(er.value.empty) } diff --git a/core/src/main/scala/cats/derived/emptyk.scala b/core/src/main/scala/cats/derived/emptyk.scala index b8ea49ff..4a2b667f 100644 --- a/core/src/main/scala/cats/derived/emptyk.scala +++ b/core/src/main/scala/cats/derived/emptyk.scala @@ -17,24 +17,23 @@ package cats.derived import alleycats.{ EmptyK, Pure } -import export.{ exports, reexports } import shapeless._ -@reexports[MkEmptyK] -object emptyk trait MkEmptyK[F[_]] extends EmptyK[F] -@exports -object MkEmptyK extends MkEmptyK0 { +object MkEmptyK extends MkEmptyKDerivation { def apply[F[_]](implicit mef: MkEmptyK[F]): MkEmptyK[F] = mef +} + +trait MkEmptyKDerivation extends MkEmptyK0 { - implicit val hnil: MkEmptyK[Const[HNil]#λ] = + implicit val mkEmptyKHnil: MkEmptyK[Const[HNil]#λ] = new MkEmptyK[Const[HNil]#λ] { def empty[A]: HNil = HNil } - implicit def hcons[F[_]](implicit ihf: IsHCons1[F, EmptyK, MkEmptyK]): MkEmptyK[F] = + implicit def mkEmptyKHcons[F[_]](implicit ihf: IsHCons1[F, EmptyK, MkEmptyK]): MkEmptyK[F] = new MkEmptyK[F] { def empty[A]: F[A] = { import ihf._ @@ -42,7 +41,7 @@ object MkEmptyK extends MkEmptyK0 { } } - implicit def ccons0[F[_]](implicit icf: IsCCons1[F, EmptyK, Trivial1]): MkEmptyK[F] = + implicit def mkEmptyKCcons0[F[_]](implicit icf: IsCCons1[F, EmptyK, Trivial1]): MkEmptyK[F] = new MkEmptyK[F] { def empty[A]: F[A] = { import icf._ @@ -52,7 +51,7 @@ object MkEmptyK extends MkEmptyK0 { } trait MkEmptyK0 extends MkEmptyK1 { - implicit def ccons1[F[_]](implicit icf: IsCCons1[F, Trivial1, MkEmptyK]): MkEmptyK[F] = + implicit def mkEmptyKCcons1[F[_]](implicit icf: IsCCons1[F, Trivial1, MkEmptyK]): MkEmptyK[F] = new MkEmptyK[F] { def empty[A]: F[A] = { import icf._ @@ -62,7 +61,7 @@ trait MkEmptyK0 extends MkEmptyK1 { } trait MkEmptyK1 extends MkEmptyK2 { - implicit def split0[F[_]](implicit split: Split1[F, EmptyK, Trivial1]): MkEmptyK[F] = + implicit def mkEmptyKSplit0[F[_]](implicit split: Split1[F, EmptyK, Trivial1]): MkEmptyK[F] = new MkEmptyK[F] { def empty[A]: F[A] = { import split._ @@ -72,7 +71,7 @@ trait MkEmptyK1 extends MkEmptyK2 { } trait MkEmptyK2 extends MkEmptyK3 { - implicit def split1[F[_]](implicit split: Split1[F, Pure, EmptyK]): MkEmptyK[F] = + implicit def mkEmptyKSplit1[F[_]](implicit split: Split1[F, Pure, EmptyK]): MkEmptyK[F] = new MkEmptyK[F] { def empty[A]: F[A] = { import split._ @@ -82,7 +81,7 @@ trait MkEmptyK2 extends MkEmptyK3 { } trait MkEmptyK3 { - implicit def generic[F[_]](implicit gen: Generic1[F, MkEmptyK]): MkEmptyK[F] = + implicit def mkEmptyKGeneric[F[_]](implicit gen: Generic1[F, MkEmptyK]): MkEmptyK[F] = new MkEmptyK[F] { def empty[A]: F[A] = gen.from(gen.fr.empty) } diff --git a/core/src/main/scala/cats/derived/eq.scala b/core/src/main/scala/cats/derived/eq.scala index f6b2fea7..f9aa111d 100644 --- a/core/src/main/scala/cats/derived/eq.scala +++ b/core/src/main/scala/cats/derived/eq.scala @@ -17,37 +17,32 @@ package cats.derived import cats.Eq -import export.{ exports, imports, reexports } import shapeless._ -@reexports[MkEq] -object eq { - @imports[Eq] - object legacy -} trait MkEq[T] extends Eq[T] -@exports -object MkEq { +object MkEq extends MkEqDerivation { def apply[T](implicit met: MkEq[T]): MkEq[T] = met +} - implicit val hnil: MkEq[HNil] = +trait MkEqDerivation { + implicit val mkEqHnil: MkEq[HNil] = new MkEq[HNil] { def eqv(a: HNil, b: HNil) = true } - implicit def hcons[H, T <: HList](implicit eqH: Lazy[Eq[H]], eqT: Lazy[MkEq[T]]): MkEq[H :: T] = + implicit def mkEqHcons[H, T <: HList](implicit eqH: Lazy[Eq[H]], eqT: Lazy[MkEq[T]]): MkEq[H :: T] = new MkEq[H :: T] { def eqv(a: H :: T, b: H :: T) = eqH.value.eqv(a.head, b.head) && eqT.value.eqv(a.tail, b.tail) } - implicit val cnil: MkEq[CNil] = + implicit val mkEqCnil: MkEq[CNil] = new MkEq[CNil] { def eqv(a: CNil, b: CNil) = true } - implicit def ccons[L, R <: Coproduct](implicit eqL: Lazy[Eq[L]], eqR: Lazy[MkEq[R]]): MkEq[L :+: R] = + implicit def mkEqCcons[L, R <: Coproduct](implicit eqL: Lazy[Eq[L]], eqR: Lazy[MkEq[R]]): MkEq[L :+: R] = new MkEq[L :+: R] { def eqv(a: L :+: R, b: L :+: R) = (a, b) match { case (Inl(l1), Inl(l2)) => eqL.value.eqv(l1, l2) @@ -56,7 +51,7 @@ object MkEq { } } - implicit def generic[T, R](implicit gen: Generic.Aux[T, R], eqR: Lazy[MkEq[R]]): MkEq[T] = + implicit def mkEqGeneric[T, R](implicit gen: Generic.Aux[T, R], eqR: Lazy[MkEq[R]]): MkEq[T] = new MkEq[T] { def eqv(a: T, b: T) = eqR.value.eqv(gen.to(a), gen.to(b)) } diff --git a/core/src/main/scala/cats/derived/foldable.scala b/core/src/main/scala/cats/derived/foldable.scala index edea5d22..2bb4309f 100644 --- a/core/src/main/scala/cats/derived/foldable.scala +++ b/core/src/main/scala/cats/derived/foldable.scala @@ -17,15 +17,8 @@ package cats.derived import cats.{ Eval, Foldable }, Eval.now -import export.{ exports, imports, reexports } import shapeless._ -@reexports[MkFoldable] -object foldable { - @imports[Foldable] - object legacy -} - trait MkFoldable[F[_]] extends Foldable[F] { def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B = safeFoldLeft(fa, b){ (b, a) => now(f(b, a)) }.value @@ -34,11 +27,12 @@ trait MkFoldable[F[_]] extends Foldable[F] { def safeFoldLeft[A, B](fa: F[A], b: B)(f: (B, A) => Eval[B]): Eval[B] } -@exports -object MkFoldable extends MkFoldable0 { +object MkFoldable extends MkFoldableDerivation { def apply[F[_]](implicit mff: MkFoldable[F]): MkFoldable[F] = mff +} - implicit val id: MkFoldable[shapeless.Id] = +trait MkFoldableDerivation extends MkFoldable0 { + implicit val mkFoldableId: MkFoldable[shapeless.Id] = new MkFoldable[shapeless.Id] { def foldRight[A, B](fa: A, lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = f(fa, lb) @@ -48,7 +42,7 @@ object MkFoldable extends MkFoldable0 { trait MkFoldable0 extends MkFoldable1 { // Induction step for products - implicit def hcons[F[_]](implicit ihc: IsHCons1[F, Foldable, MkFoldable]): MkFoldable[F] = + implicit def mkFoldableHcons[F[_]](implicit ihc: IsHCons1[F, Foldable, MkFoldable]): MkFoldable[F] = new MkFoldable[F] { def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = { import ihc._ @@ -70,7 +64,7 @@ trait MkFoldable0 extends MkFoldable1 { } // Induction step for coproducts - implicit def ccons[F[_]](implicit icc: IsCCons1[F, Foldable, MkFoldable]): MkFoldable[F] = + implicit def mkFoldableCcons[F[_]](implicit icc: IsCCons1[F, Foldable, MkFoldable]): MkFoldable[F] = new MkFoldable[F] { def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = { import icc._ @@ -91,7 +85,7 @@ trait MkFoldable0 extends MkFoldable1 { } trait MkFoldable1 extends MkFoldable2 { - implicit def split[F[_]](implicit split: Split1[F, Foldable, Foldable]): MkFoldable[F] = + implicit def mkFoldableSplit[F[_]](implicit split: Split1[F, Foldable, Foldable]): MkFoldable[F] = new MkFoldable[F] { def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = { import split._ @@ -106,7 +100,7 @@ trait MkFoldable1 extends MkFoldable2 { } trait MkFoldable2 extends MkFoldable3 { - implicit def generic[F[_]](implicit gen: Generic1[F, MkFoldable]): MkFoldable[F] = + implicit def mkFoldableGeneric[F[_]](implicit gen: Generic1[F, MkFoldable]): MkFoldable[F] = new MkFoldable[F] { def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = gen.fr.foldRight(gen.to(fa), lb)(f) @@ -117,7 +111,7 @@ trait MkFoldable2 extends MkFoldable3 { } trait MkFoldable3 { - implicit def constFoldable[T]: MkFoldable[Const[T]#λ] = + implicit def mkFoldableConstFoldable[T]: MkFoldable[Const[T]#λ] = new MkFoldable[Const[T]#λ] { def foldRight[A, B](fa: T, lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = lb diff --git a/core/src/main/scala/cats/derived/functor.scala b/core/src/main/scala/cats/derived/functor.scala index 4a40709e..aed53fd5 100644 --- a/core/src/main/scala/cats/derived/functor.scala +++ b/core/src/main/scala/cats/derived/functor.scala @@ -17,14 +17,8 @@ package cats.derived import cats.{ Eval, Functor }, Eval.now -import export.{ exports, imports, reexports } import shapeless._ -@reexports[MkFunctor] -object functor { - @imports[Functor] - object legacy -} trait MkFunctor[F[_]] extends Functor[F] { def map[A, B](fa: F[A])(f: A => B): F[B] = safeMap(fa){ a => now(f(a)) }.value @@ -32,14 +26,13 @@ trait MkFunctor[F[_]] extends Functor[F] { def safeMap[A, B](fa: F[A])(f: A => Eval[B]): Eval[F[B]] } -@exports -object MkFunctor extends MkFunctor0 { +object MkFunctor extends MkFunctorDerivation { def apply[F[_]](implicit mff: MkFunctor[F]): MkFunctor[F] = mff } -trait MkFunctor0 extends MkFunctor1 { +trait MkFunctorDerivation extends MkFunctor1 { // Induction step for products - implicit def hcons[F[_]](implicit ihc: IsHCons1[F, Functor, MkFunctor]): MkFunctor[F] = + implicit def mkFunctorHcons[F[_]](implicit ihc: IsHCons1[F, Functor, MkFunctor]): MkFunctor[F] = new MkFunctor[F] { def safeMap[A, B](fa: F[A])(f: A => Eval[B]): Eval[F[B]] = { import ihc._ @@ -52,7 +45,7 @@ trait MkFunctor0 extends MkFunctor1 { } // Induction step for coproducts - implicit def ccons[F[_]](implicit icc: IsCCons1[F, Functor, MkFunctor]): MkFunctor[F] = + implicit def mkFunctorCcons[F[_]](implicit icc: IsCCons1[F, Functor, MkFunctor]): MkFunctor[F] = new MkFunctor[F] { def safeMap[A, B](fa: F[A])(f: A => Eval[B]): Eval[F[B]] = { import icc._ @@ -65,7 +58,7 @@ trait MkFunctor0 extends MkFunctor1 { } trait MkFunctor1 extends MkFunctor2 { - implicit def split[F[_]](implicit split: Split1[F, Functor, Functor]): MkFunctor[F] = + implicit def mkFunctorSplit[F[_]](implicit split: Split1[F, Functor, Functor]): MkFunctor[F] = new MkFunctor[F] { def safeMap[A, B](fa: F[A])(f: A => Eval[B]): Eval[F[B]] = { import split._ @@ -75,7 +68,7 @@ trait MkFunctor1 extends MkFunctor2 { } trait MkFunctor2 extends MkFunctor3 { - implicit def generic[F[_]](implicit gen: Generic1[F, MkFunctor]): MkFunctor[F] = + implicit def mkFunctorGeneric[F[_]](implicit gen: Generic1[F, MkFunctor]): MkFunctor[F] = new MkFunctor[F] { def safeMap[A, B](fa: F[A])(f: A => Eval[B]): Eval[F[B]] = gen.fr.safeMap(gen.to(fa))(f).map(gen.from) @@ -83,7 +76,7 @@ trait MkFunctor2 extends MkFunctor3 { } trait MkFunctor3 { - implicit def constFunctor[T]: MkFunctor[Const[T]#λ] = + implicit def mkFunctorConstFunctor[T]: MkFunctor[Const[T]#λ] = new MkFunctor[Const[T]#λ] { def safeMap[A, B](t: T)(f: A => Eval[B]): Eval[T] = now(t) } diff --git a/core/src/main/scala/cats/derived/iterable.scala b/core/src/main/scala/cats/derived/iterable.scala index f3a54bde..df3f79c0 100644 --- a/core/src/main/scala/cats/derived/iterable.scala +++ b/core/src/main/scala/cats/derived/iterable.scala @@ -20,11 +20,11 @@ import scala.annotation.tailrec import shapeless._ -object iterable { - object legacy { - implicit def mkIterableLegacy[F[_], A](fa: F[A])(implicit mif: MkIterable[F]): Iterable[A] = - mif.iterable(fa) - } +trait IterableDerivationFromMkIterable { + + implicit def mkIterableLegacy[F[_], A](fa: F[A])(implicit mif: MkIterable[F]): Iterable[A] = + mif.iterable(fa) + } trait MkIterable[F[_]] { @@ -93,17 +93,17 @@ object MkIterable extends MkIterable0 { def apply[F[_]](implicit mif: MkIterable[F]): MkIterable[F] = mif - implicit val id: MkIterable[Id] = + implicit val mkIterableId: MkIterable[Id] = new MkIterable[Id] { def initialState[A](fa: A): IterState[A] = Return(fa) } - implicit val option: MkIterable[Option] = + implicit val mkIterableOption: MkIterable[Option] = new MkIterable[Option] { def initialState[A](fa: Option[A]): IterState[A] = ReturnI(fa.iterator) } - implicit def iterable[F[t] <: Iterable[t]]: MkIterable[F] = + implicit def mkIterableIterable[F[t] <: Iterable[t]]: MkIterable[F] = new MkIterable[F] { def initialState[A](fa: F[A]): IterState[A] = ReturnI(fa.iterator) @@ -113,7 +113,7 @@ object MkIterable extends MkIterable0 { trait MkIterable0 extends MkIterable1 { import IterState._ - implicit def hcons[F[_]](implicit F: IsHCons1[F, MkIterable, MkIterable]): MkIterable[F] = + implicit def mkIterableHcons[F[_]](implicit F: IsHCons1[F, MkIterable, MkIterable]): MkIterable[F] = new MkIterable[F] { def initialState[A](fa: F[A]): IterState[A] = { val (hd, tl) = F.unpack(fa) @@ -122,7 +122,7 @@ trait MkIterable0 extends MkIterable1 { } } - implicit def ccons[F[_]](implicit F: IsCCons1[F, MkIterable, MkIterable]): MkIterable[F] = + implicit def mkIterableCcons[F[_]](implicit F: IsCCons1[F, MkIterable, MkIterable]): MkIterable[F] = new MkIterable[F] { def initialState[A](fa: F[A]): IterState[A] = { F.unpack(fa) match { @@ -136,7 +136,7 @@ trait MkIterable0 extends MkIterable1 { trait MkIterable1 extends MkIterable2 { import IterState._ - implicit def split[F[_]](implicit split: Split1[F, MkIterable, MkIterable]): MkIterable[F] = + implicit def mkIterableCplit[F[_]](implicit split: Split1[F, MkIterable, MkIterable]): MkIterable[F] = new MkIterable[F] { def initialState[A](fa: F[A]): IterState[A] = { import split._ @@ -146,7 +146,7 @@ trait MkIterable1 extends MkIterable2 { } trait MkIterable2 extends MkIterable3 { - implicit def generic[F[_]](implicit F: Generic1[F, MkIterable]): MkIterable[F] = + implicit def mkIterableGeneric[F[_]](implicit F: Generic1[F, MkIterable]): MkIterable[F] = new MkIterable[F] { def initialState[A](fa: F[A]): IterState[A] = F.fr.initialState(F.to(fa)) } @@ -155,7 +155,7 @@ trait MkIterable2 extends MkIterable3 { trait MkIterable3 { import IterState._ - implicit def const[T]: MkIterable[Const[T]#λ] = + implicit def mkIterableConst[T]: MkIterable[Const[T]#λ] = new MkIterable[Const[T]#λ] { def initialState[A](fa: T): IterState[A] = Done } diff --git a/core/src/main/scala/cats/derived/monad.scala b/core/src/main/scala/cats/derived/monad.scala deleted file mode 100644 index 5e6eb5b6..00000000 --- a/core/src/main/scala/cats/derived/monad.scala +++ /dev/null @@ -1,72 +0,0 @@ -package cats.derived - -import cats._, Eval.now -import alleycats.{ConsK, EmptyK, Pure} -import export.{ exports, imports, reexports } -import shapeless._ - - -@reexports[MkMonad] -object monad { - @imports[Monad] - object legacy -} - -trait MkMonad[F[_]] extends Monad[F] - -@exports -object MkMonad extends MkMonad0 { - def apply[F[_]](implicit mmf: MkMonad[F]): MkMonad[F] = mmf -} - - -private[derived] sealed abstract class MkMonad0 extends MkMonad1 { - implicit def withConsK[F[_]]( - implicit - P: Cached[Pure[F]], - C: Cached[ConsK[F]], - E: Cached[EmptyK[F]], - F: Cached[Foldable[F]] - ): MkMonad[F] = new MkMonad[F] with UnsafeTailRecM[F] { - def pure[A](x: A): F[A] = P.value.pure(x) - - def flatMap[A, B](fa: F[A])(f: (A) => F[B]): F[B] = { - F.value.foldRight[A, F[B]](fa, now(E.value.empty[B])) { (a, l) => - val fb = f(a) - F.value.foldRight(fb, l)((b, memo) => now(C.value.cons(b, memo.value))) - }.value - } - - } -} - - -private[derived] sealed abstract class MkMonad1 { - implicit def withoutConsK[F[_]]( - implicit - P: Cached[Pure[F]], - E: Cached[EmptyK[F]], - F: Cached[Foldable[F]] - ): MkMonad[F] = new MkMonad[F] with UnsafeTailRecM[F] { - def pure[A](x: A): F[A] = P.value.pure(x) - - def flatMap[A, B](fa: F[A])(f: (A) => F[B]): F[B] = { - F.value.foldLeft[A, F[B]](fa, E.value.empty[B])((_, a) => f(a)) - } - - - } - - - /** - * todo: implement a stack safe version - */ - trait UnsafeTailRecM[F[_]] extends Monad[F] { - override def tailRecM[A, B](a: A)(f: (A) => F[Either[A, B]]): F[B] = flatMap(f(a)) { - case Right(b) => pure(b) - case Left(nextA) => tailRecM(nextA)(f) - } - } -} - - diff --git a/core/src/main/scala/cats/derived/monoid.scala b/core/src/main/scala/cats/derived/monoid.scala index 5f7253d2..f81b9dea 100644 --- a/core/src/main/scala/cats/derived/monoid.scala +++ b/core/src/main/scala/cats/derived/monoid.scala @@ -17,22 +17,16 @@ package cats.derived import cats.Monoid -import export.{ exports, imports, reexports } import shapeless._ -@reexports[MkEmpty, MkMonoid, MkSemigroup] -object monoid { - @imports[Monoid] - object legacy -} - trait MkMonoid[T] extends Monoid[T] -@exports(Algebraic) -object MkMonoid { +object MkMonoid extends MkMonoidDerivation { def apply[T](implicit m: MkMonoid[T]): MkMonoid[T] = m +} - implicit def algebraic[T](implicit e: Lazy[MkEmpty[T]], sg: Lazy[MkSemigroup[T]]) +trait MkMonoidDerivation { + implicit def mkMonoidAlgebraic[T](implicit e: Lazy[MkEmpty[T]], sg: Lazy[MkSemigroup[T]]) : MkMonoid[T] = new MkMonoid[T] { def empty = e.value.empty def combine(x: T, y: T) = sg.value.combine(x, y) diff --git a/core/src/main/scala/cats/derived/monoidk.scala b/core/src/main/scala/cats/derived/monoidk.scala index 92f48103..1fb28875 100644 --- a/core/src/main/scala/cats/derived/monoidk.scala +++ b/core/src/main/scala/cats/derived/monoidk.scala @@ -17,28 +17,22 @@ package cats.derived import cats.{ Applicative, Monoid, MonoidK } -import export.{ exports, imports, reexports } import shapeless._ -@reexports[MkMonoidK] -object monoidk { - @imports[MonoidK] - object legacy -} - trait MkMonoidK[F[_]] extends MonoidK[F] -@exports -object MkMonoidK extends MkMonoidK0 { +object MkMonoidK extends MkMonoidKDerivation { def apply[F[_]](implicit mk: MkMonoidK[F]): MkMonoidK[F] = mk +} - implicit val hnil: MkMonoidK[Const[HNil]#λ] = +trait MkMonoidKDerivation extends MkMonoidK0 { + implicit val mkMonoidKHnil: MkMonoidK[Const[HNil]#λ] = new MkMonoidK[Const[HNil]#λ] { def empty[A] = HNil def combineK[A](x: HNil, y: HNil) = HNil } - implicit def hcons[F[_]](implicit ihc: IsHCons1[F, MonoidK, MkMonoidK]) + implicit def mkMonoidKHcons[F[_]](implicit ihc: IsHCons1[F, MonoidK, MkMonoidK]) : MkMonoidK[F] = new MkMonoidK[F] { import ihc._ def empty[A] = pack(fh.empty, ft.empty) @@ -51,7 +45,7 @@ object MkMonoidK extends MkMonoidK0 { } trait MkMonoidK0 extends MkMonoidK1 { - implicit def composed[F[_]](implicit split: Split1[F, MonoidK, Trivial1]) + implicit def mkMonoidKComposed[F[_]](implicit split: Split1[F, MonoidK, Trivial1]) : MkMonoidK[F] = new MkMonoidK[F] { import split._ def empty[A] = pack(fo.empty[I[A]]) @@ -61,7 +55,7 @@ trait MkMonoidK0 extends MkMonoidK1 { } trait MkMonoidK1 extends MkMonoidK2 { - implicit def applicative[F[_]](implicit split: Split1[F, Applicative, MonoidK]) + implicit def mkMonoidKApplicative[F[_]](implicit split: Split1[F, Applicative, MonoidK]) : MkMonoidK[F] = new MkMonoidK[F] { import split._ def empty[A] = pack(fo.pure(fi.empty[A])) @@ -71,7 +65,7 @@ trait MkMonoidK1 extends MkMonoidK2 { } trait MkMonoidK2 extends MkMonoidK3 { - implicit def generic[F[_]](implicit gen: Generic1[F, MkMonoidK]) + implicit def mkMonoidKGeneric[F[_]](implicit gen: Generic1[F, MkMonoidK]) : MkMonoidK[F] = new MkMonoidK[F] { import gen._ def empty[A] = from(fr.empty) @@ -81,7 +75,7 @@ trait MkMonoidK2 extends MkMonoidK3 { } trait MkMonoidK3 { - implicit def const[T](implicit m: Monoid[T]) + implicit def mkMonoidKConst[T](implicit m: Monoid[T]) : MkMonoidK[Const[T]#λ] = new MkMonoidK[Const[T]#λ] { def empty[A] = m.empty def combineK[A](x: T, y: T) = m.combine(x, y) diff --git a/core/src/main/scala/cats/derived/package.scala b/core/src/main/scala/cats/derived/package.scala new file mode 100644 index 00000000..f53f89cc --- /dev/null +++ b/core/src/main/scala/cats/derived/package.scala @@ -0,0 +1,19 @@ +package cats + +/** + * For backward compat purpose. + * Use cats.derive to explicitly derive instance instead + */ +package object derived { + object emptyK extends MkEmptyKDerivation + object eq extends MkEqDerivation + object foldable extends MkFoldableDerivation + object functor extends MkFunctorDerivation + object iterable extends IterableDerivationFromMkIterable + object monoid extends MkMonoidDerivation + object monoidK extends MkMonoidKDerivation + object pure extends MkPureDerivation + object semigroup extends MkSemigroupDerivation + object semigroupK extends MkSemigroupKDerivation + object show extends MkShowDerivation +} diff --git a/core/src/main/scala/cats/derived/pure.scala b/core/src/main/scala/cats/derived/pure.scala index f59a6e8f..8fe41e04 100644 --- a/core/src/main/scala/cats/derived/pure.scala +++ b/core/src/main/scala/cats/derived/pure.scala @@ -16,20 +16,18 @@ package cats.derived -import alleycats.{ EmptyK, Pure } -import export.{ exports, reexports } +import alleycats.{EmptyK, Pure} import shapeless._ -@reexports[MkPure] -object pure trait MkPure[F[_]] extends Pure[F] -@exports -object MkPure extends MkPure0 { +object MkPure extends MkPureDerivation { def apply[F[_]](implicit mpf: MkPure[F]): MkPure[F] = mpf +} - implicit def hcons0[F[_]](implicit ihf: IsHCons1[F, Pure, MkEmptyK]): MkPure[F] = +trait MkPureDerivation extends MkPure0 { + implicit def mkPureHcons0[F[_]](implicit ihf: IsHCons1[F, Pure, EmptyK]): MkPure[F] = new MkPure[F] { def pure[A](a: A): F[A] = { import ihf._ @@ -37,7 +35,7 @@ object MkPure extends MkPure0 { } } - implicit def ccons0[F[_]](implicit icf: IsCCons1[F, Pure, Trivial1]): MkPure[F] = + implicit def mkPureCcons0[F[_]](implicit icf: IsCCons1[F, Pure, Trivial1]): MkPure[F] = new MkPure[F] { def pure[A](a: A): F[A] = { import icf._ @@ -47,7 +45,7 @@ object MkPure extends MkPure0 { } trait MkPure0 extends MkPure1 { - implicit def hcons1[F[_]](implicit ihf: IsHCons1[F, EmptyK, MkPure]): MkPure[F] = + implicit def mkPureHcons1[F[_]](implicit ihf: IsHCons1[F, EmptyK, MkPure]): MkPure[F] = new MkPure[F] { def pure[A](a: A): F[A] = { import ihf._ @@ -55,7 +53,7 @@ trait MkPure0 extends MkPure1 { } } - implicit def ccons1[F[_]](implicit icf: IsCCons1[F, Trivial1, MkPure]): MkPure[F] = + implicit def mkPureCcons1[F[_]](implicit icf: IsCCons1[F, Trivial1, MkPure]): MkPure[F] = new MkPure[F] { def pure[A](a: A): F[A] = { import icf._ @@ -65,7 +63,7 @@ trait MkPure0 extends MkPure1 { } trait MkPure1 extends MkPure2 { - implicit def split[F[_]](implicit split: Split1[F, Pure, Pure]): MkPure[F] = + implicit def mkPureSplit[F[_]](implicit split: Split1[F, Pure, Pure]): MkPure[F] = new MkPure[F] { def pure[A](a: A): F[A] = { import split._ @@ -75,7 +73,7 @@ trait MkPure1 extends MkPure2 { } trait MkPure2 { - implicit def generic[F[_]](implicit gen: Generic1[F, MkPure]): MkPure[F] = + implicit def mkPureGeneric[F[_]](implicit gen: Generic1[F, MkPure]): MkPure[F] = new MkPure[F] { def pure[A](a: A): F[A] = gen.from(gen.fr.pure(a)) } diff --git a/core/src/main/scala/cats/derived/semigroup.scala b/core/src/main/scala/cats/derived/semigroup.scala index c31f7774..a9af5ee5 100644 --- a/core/src/main/scala/cats/derived/semigroup.scala +++ b/core/src/main/scala/cats/derived/semigroup.scala @@ -17,34 +17,29 @@ package cats.derived import cats.Semigroup -import export.{ exports, imports, reexports } import shapeless._ -@reexports[MkSemigroup] -object semigroup { - @imports[Semigroup] - object legacy -} trait MkSemigroup[T] extends Semigroup[T] -@exports -object MkSemigroup { +object MkSemigroup extends MkSemigroupDerivation { def apply[T](implicit met: MkSemigroup[T]): MkSemigroup[T] = met +} - implicit val hnil: MkSemigroup[HNil] = +trait MkSemigroupDerivation { + implicit val mkSemigroupHnil: MkSemigroup[HNil] = new MkSemigroup[HNil] { def combine(a: HNil, b: HNil) = HNil } - implicit def hcons[H, T <: HList](implicit semigroupH: Lazy[Semigroup[H]], semigroupT: Lazy[MkSemigroup[T]]): MkSemigroup[H :: T] = + implicit def mkSemigroupHcons[H, T <: HList](implicit semigroupH: Lazy[Semigroup[H]], semigroupT: Lazy[MkSemigroup[T]]): MkSemigroup[H :: T] = new MkSemigroup[H :: T] { def combine(a: H :: T, b: H :: T) = semigroupH.value.combine(a.head, b.head) :: semigroupT.value.combine(a.tail, b.tail) } - implicit def generic[T, R]( + implicit def mkSemigroupGeneric[T, R]( implicit gen: Generic.Aux[T, R], semigroupR: Lazy[MkSemigroup[R]]): MkSemigroup[T] = new MkSemigroup[T] { def combine(a: T, b: T) = gen.from(semigroupR.value.combine(gen.to(a), gen.to(b))) diff --git a/core/src/main/scala/cats/derived/semigroupk.scala b/core/src/main/scala/cats/derived/semigroupk.scala index 74426964..bc2af8ce 100644 --- a/core/src/main/scala/cats/derived/semigroupk.scala +++ b/core/src/main/scala/cats/derived/semigroupk.scala @@ -17,28 +17,23 @@ package cats.derived import cats.{ Apply, Semigroup, SemigroupK } -import export.{ exports, imports, reexports } import shapeless._ -@reexports[MkSemigroupK] -object semigroupk { - @imports[SemigroupK] - object legacy -} trait MkSemigroupK[F[_]] extends SemigroupK[F] -@exports -object MkSemigroupK extends MkSemigroupK0 { +object MkSemigroupK extends MkSemigroupKDerivation { def apply[F[_]](implicit sgk: MkSemigroupK[F]): MkSemigroupK[F] = sgk +} - implicit val hnil: MkSemigroupK[Const[HNil]#λ] = +trait MkSemigroupKDerivation extends MkSemigroupK0 { + implicit val mkSemigroupKHnil: MkSemigroupK[Const[HNil]#λ] = new MkSemigroupK[Const[HNil]#λ] { def empty[A] = HNil def combineK[A](x: HNil, y: HNil) = HNil } - implicit def hcons[F[_]](implicit ihc: IsHCons1[F, SemigroupK, MkSemigroupK]) + implicit def mkSemigroupKHcons[F[_]](implicit ihc: IsHCons1[F, SemigroupK, MkSemigroupK]) : MkSemigroupK[F] = new MkSemigroupK[F] { import ihc._ def combineK[A](x: F[A], y: F[A]) = { @@ -50,7 +45,7 @@ object MkSemigroupK extends MkSemigroupK0 { } trait MkSemigroupK0 extends MkSemigroupK1 { - implicit def composed[F[_]](implicit split: Split1[F, SemigroupK, Trivial1]) + implicit def mkSemigroupKComposed[F[_]](implicit split: Split1[F, SemigroupK, Trivial1]) : MkSemigroupK[F] = new MkSemigroupK[F] { import split._ def combineK[A](x: F[A], y: F[A]) = @@ -59,7 +54,7 @@ trait MkSemigroupK0 extends MkSemigroupK1 { } trait MkSemigroupK1 extends MkSemigroupK2 { - implicit def applied[F[_]](implicit split: Split1[F, Apply, SemigroupK]) + implicit def mkSemigroupKApplied[F[_]](implicit split: Split1[F, Apply, SemigroupK]) : MkSemigroupK[F] = new MkSemigroupK[F] { import split._ def combineK[A](x: F[A], y: F[A]) = @@ -68,7 +63,7 @@ trait MkSemigroupK1 extends MkSemigroupK2 { } trait MkSemigroupK2 extends MkSemigroupK3 { - implicit def generic[F[_]](implicit gen: Generic1[F, MkSemigroupK]) + implicit def mkSemigroupKGeneric[F[_]](implicit gen: Generic1[F, MkSemigroupK]) : MkSemigroupK[F] = new MkSemigroupK[F] { import gen._ def combineK[A](x: F[A], y: F[A]) = @@ -77,7 +72,7 @@ trait MkSemigroupK2 extends MkSemigroupK3 { } trait MkSemigroupK3 { - implicit def const[T](implicit sg: Semigroup[T]) + implicit def mkSemigroupKConst[T](implicit sg: Semigroup[T]) : MkSemigroupK[Const[T]#λ] = new MkSemigroupK[Const[T]#λ] { def combineK[A](x: T, y: T) = sg.combine(x, y) } diff --git a/core/src/main/scala/cats/derived/show.scala b/core/src/main/scala/cats/derived/show.scala index a4faec12..b9aa33bb 100644 --- a/core/src/main/scala/cats/derived/show.scala +++ b/core/src/main/scala/cats/derived/show.scala @@ -1,12 +1,8 @@ package cats.derived import cats.Show -import export.{ exports, reexports } import shapeless._, labelled._ -@reexports[MkShow] -object show - /** * Due to a limitation in the way Shapeless' `describe` is currently * implemented, `Show` can't be derived for ADTs which are _both_ @@ -21,19 +17,33 @@ object show */ trait MkShow[A] extends Show[A] -@exports -object MkShow { - private def instance[A](body: A => String) = new Show[A] { - def show(value: A): String = body(value) - } +object MkShow extends MkShowDerivation { + def apply[A](implicit show: MkShow[A]): MkShow[A] = show +} + +trait MkShowDerivation extends MkShow0 { - implicit def emptyProductDerivedShow: Show[HNil] = + implicit def emptyProductDerivedShow: MkShow[HNil] = instance(_ => "") + // used when a Show[V] (a member of the coproduct) is readily available + implicit def productDerivedShowWhenShowVAvailable[K <: Symbol, V, T <: HList]( + implicit key: Witness.Aux[K], + showV: Lazy[Show[V]], + showT: MkShow[T]): MkShow[FieldType[K, V] :: T] = mkShowCons +} + +trait MkShow0 extends MkShow1 { + // used when a Show[V] (a member of the product) needs to be derived implicit def productDerivedShow[K <: Symbol, V, T <: HList]( - implicit key: Witness.Aux[K], - showV: Lazy[Show[V]], - showT: Show[T]): Show[FieldType[K, V] :: T] = instance { fields => + implicit key: Witness.Aux[K], + showV: Lazy[MkShow[V]], + showT: MkShow[T]): MkShow[FieldType[K, V] :: T] = mkShowCons + + def mkShowCons[K <: Symbol, V, T <: HList]( + implicit key: Witness.Aux[K], + showV: Lazy[Show[V]], + showT: MkShow[T]): MkShow[FieldType[K, V] :: T] = instance { fields => val fieldName = key.value.name val fieldValue = showV.value.show(fields.head) val nextFields = showT.show(fields.tail) @@ -44,29 +54,53 @@ object MkShow { s"$fieldName = $fieldValue, $nextFields" } - implicit def emptyCoproductDerivedShow: Show[CNil] = + + implicit def emptyCoproductDerivedShow: MkShow[CNil] = sys.error("Kittens derived Show instance: impossible to call `show` on `CNil`") +} +trait MkShow1 extends MkShow2 { + // used when a Show[V] (a member of the coproduct) is readily available + implicit def coproductDerivedShowWhenShowVAvailable[K <: Symbol, V, T <: Coproduct]( + implicit key: Witness.Aux[K], + showV: Lazy[Show[V]], + showT: Lazy[MkShow[T]]): MkShow[FieldType[K, V] :+: T] = mkShowCoproduct + +} + +trait MkShow2 extends MkShow3 { + // used when Show[V] (a member of the coproduct) has to be derived. implicit def coproductDerivedShow[K <: Symbol, V, T <: Coproduct]( - implicit key: Witness.Aux[K], - showV: Lazy[Show[V]], - showT: Lazy[Show[T]]): Show[FieldType[K, V] :+: T] = instance { - case Inl(l) => showV.value.show(l) - case Inr(r) => showT.value.show(r) + implicit key: Witness.Aux[K], + showV: Lazy[MkShow[V]], + showT: Lazy[MkShow[T]]): MkShow[FieldType[K, V] :+: T] = mkShowCoproduct + + def mkShowCoproduct[K <: Symbol, V, T <: Coproduct]( + implicit key: Witness.Aux[K], + showV: Lazy[Show[V]], + showT: Lazy[MkShow[T]]): MkShow[FieldType[K, V] :+: T] = instance { + case Inl(l) => showV.value.show(l) + case Inr(r) => showT.value.show(r) } implicit def genericDerivedShowProduct[A, R <: HList]( - implicit repr: LabelledGeneric.Aux[A, R], - t: Lazy[Typeable[A]], - s: Lazy[Show[R]]): Show[A] = instance { a => + implicit repr: LabelledGeneric.Aux[A, R], + t: Lazy[Typeable[A]], + s: Lazy[MkShow[R]]): MkShow[A] = instance { a => val name = t.value.describe.takeWhile(_ != '[') val contents = s.value.show(repr.to(a)) s"$name($contents)" } +} + +trait MkShow3 { + protected def instance[A](body: A => String): MkShow[A] = new MkShow[A] { + def show(value: A): String = body(value) + } implicit def genericDerivedShowCoproduct[A, R <: Coproduct]( implicit repr: LabelledGeneric.Aux[A, R], - s: Lazy[Show[R]]): Show[A] = + s: Lazy[MkShow[R]]): MkShow[A] = instance(a => s.value.show(repr.to(a))) } diff --git a/core/src/main/scala/cats/sequence/sequence.scala b/core/src/main/scala/cats/sequence/sequence.scala index eac70d9f..f35331a4 100644 --- a/core/src/main/scala/cats/sequence/sequence.scala +++ b/core/src/main/scala/cats/sequence/sequence.scala @@ -6,8 +6,8 @@ package cats.sequence import shapeless._ -import cats.{Functor, Apply} -import shapeless.ops.hlist.ZipWithKeys +import cats.{Apply, Functor} +import shapeless.ops.hlist.{Align, ZipWithKeys} import shapeless.ops.record.{Keys, Values} import scala.annotation.implicitNotFound @@ -95,18 +95,19 @@ object GenericSequencer extends MkGenericSequencer { trait MkGenericSequencer { - implicit def mkGenericSequencer[L <: HList, T, SOut <: HList, FOut, F[_]] + implicit def mkGenericSequencer[L <: HList, T, SOut <: HList, FOut, LOut <: HList, F[_]] ( implicit rs: RecordSequencer.Aux[L, FOut], - gen: LabelledGeneric.Aux[T, SOut], + gen: LabelledGeneric.Aux[T, LOut], eqv: FOut =:= F[SOut], + align: Align[SOut, LOut], F: Functor[F] ): GenericSequencer.Aux[L, T, F[T]] = new GenericSequencer[L, T] { type Out = F[T] def apply(in: L): Out = { - F.map(rs(in))(gen.from) + F.map(rs(in))(l => gen.from(l.align)) } } } diff --git a/core/src/test/scala/cats/derived/empty.scala b/core/src/test/scala/cats/derived/empty.scala index 67e87f49..70195a1a 100644 --- a/core/src/test/scala/cats/derived/empty.scala +++ b/core/src/test/scala/cats/derived/empty.scala @@ -19,7 +19,7 @@ package cats.derived import alleycats.Empty import cats.instances.all._ -import empty._, legacy._ +import MkEmpty._ import TestDefns._ class EmptyTests extends KittensSuite { diff --git a/core/src/test/scala/cats/derived/emptyk.scala b/core/src/test/scala/cats/derived/emptyk.scala index 258e7073..35cea491 100644 --- a/core/src/test/scala/cats/derived/emptyk.scala +++ b/core/src/test/scala/cats/derived/emptyk.scala @@ -16,12 +16,10 @@ package cats.derived -import alleycats.EmptyK, alleycats.std.all._ -import cats._ -import shapeless._ +import alleycats.EmptyK import TestDefns._ -import emptyk._, pure._ +import emptyK._ class EmptyKTests extends KittensSuite { @@ -45,7 +43,7 @@ class EmptyKTests extends KittensSuite { test("EmptyK[λ[t => Option[Option[t]]]]") { type OOption[t] = Option[Option[t]] - val E = MkEmptyK[OOption] + val E = EmptyK[OOption] assert(E.empty == None) } diff --git a/core/src/test/scala/cats/derived/eq.scala b/core/src/test/scala/cats/derived/eq.scala index d382ecf4..fc22e34e 100644 --- a/core/src/test/scala/cats/derived/eq.scala +++ b/core/src/test/scala/cats/derived/eq.scala @@ -18,7 +18,7 @@ package cats.derived import cats.Eq import cats.kernel.laws.OrderLaws -import eq._, legacy._ +import eq._ import org.scalacheck.Prop.forAll import org.scalacheck.Arbitrary, Arbitrary.arbitrary diff --git a/core/src/test/scala/cats/derived/foldable.scala b/core/src/test/scala/cats/derived/foldable.scala index 68bd2586..76c1ac6c 100644 --- a/core/src/test/scala/cats/derived/foldable.scala +++ b/core/src/test/scala/cats/derived/foldable.scala @@ -29,7 +29,7 @@ class FoldableTests extends KittensSuite { if (a === goal) now(true) else lb } - import foldable._, legacy._ + import foldable._ import cats.instances.int._ test("Foldable[IList]") { diff --git a/core/src/test/scala/cats/derived/functor.scala b/core/src/test/scala/cats/derived/functor.scala index 4fad6cca..5637c85c 100644 --- a/core/src/test/scala/cats/derived/functor.scala +++ b/core/src/test/scala/cats/derived/functor.scala @@ -14,15 +14,15 @@ * limitations under the License. */ -package cats.derived +package cats +package derived import cats.Functor import TestDefns._ -import functor._, legacy._ -import iterable.legacy._ -import shapeless.cachedImplicit +import functor._ +import iterable._ class FunctorTests extends KittensSuite { diff --git a/core/src/test/scala/cats/derived/iterable.scala b/core/src/test/scala/cats/derived/iterable.scala index 8b2d585d..0b644ab0 100644 --- a/core/src/test/scala/cats/derived/iterable.scala +++ b/core/src/test/scala/cats/derived/iterable.scala @@ -16,7 +16,7 @@ package cats.derived -import TestDefns._, iterable.legacy._ +import TestDefns._, iterable._ class IterableTests extends KittensSuite { diff --git a/core/src/test/scala/cats/derived/monoid.scala b/core/src/test/scala/cats/derived/monoid.scala index 7992a246..e9865bd1 100644 --- a/core/src/test/scala/cats/derived/monoid.scala +++ b/core/src/test/scala/cats/derived/monoid.scala @@ -19,7 +19,7 @@ package cats.derived import cats._, instances.all._, kernel.laws.GroupLaws import org.scalacheck.Arbitrary, Arbitrary.arbitrary -import monoid._, legacy._ +import monoid._ import TestDefns._ class MonoidTests extends KittensSuite { diff --git a/core/src/test/scala/cats/derived/monoidk.scala b/core/src/test/scala/cats/derived/monoidk.scala index e4676b83..42b1a0c9 100644 --- a/core/src/test/scala/cats/derived/monoidk.scala +++ b/core/src/test/scala/cats/derived/monoidk.scala @@ -18,7 +18,7 @@ package cats.derived import cats._, instances.all._, kernel.laws.GroupLaws -import monoidk._, legacy._ +import monoidK._ class MonoidKTests extends KittensSuite { import SemigroupKTests.ComplexProduct diff --git a/core/src/test/scala/cats/derived/pure.scala b/core/src/test/scala/cats/derived/pure.scala index 7f8c405b..64b25635 100644 --- a/core/src/test/scala/cats/derived/pure.scala +++ b/core/src/test/scala/cats/derived/pure.scala @@ -21,7 +21,7 @@ import cats._ import shapeless.{ Id => _, _ } import TestDefns._ -import emptyk._, pure._ +import pure._, emptyK._ class PureTests extends KittensSuite { diff --git a/core/src/test/scala/cats/derived/semigroup.scala b/core/src/test/scala/cats/derived/semigroup.scala index 85e8636a..5404b64e 100644 --- a/core/src/test/scala/cats/derived/semigroup.scala +++ b/core/src/test/scala/cats/derived/semigroup.scala @@ -17,7 +17,7 @@ package cats.derived import cats.Semigroup -import semigroup._, legacy._ +import semigroup._ import org.scalacheck.Prop.forAll import org.scalacheck.Arbitrary, Arbitrary.arbitrary import TestDefns._ diff --git a/core/src/test/scala/cats/derived/semigroupk.scala b/core/src/test/scala/cats/derived/semigroupk.scala index 79b9ccaf..7612fc5d 100644 --- a/core/src/test/scala/cats/derived/semigroupk.scala +++ b/core/src/test/scala/cats/derived/semigroupk.scala @@ -19,7 +19,7 @@ package cats.derived import cats._, instances.all._, kernel.laws.GroupLaws import org.scalacheck.Arbitrary, Arbitrary.arbitrary -import semigroupk._, legacy._ +import semigroupK._ class SemigroupKTests extends KittensSuite { import SemigroupKTests.ComplexProduct diff --git a/core/src/test/scala/cats/derived/show.scala b/core/src/test/scala/cats/derived/show.scala index c7fc2201..3481e334 100644 --- a/core/src/test/scala/cats/derived/show.scala +++ b/core/src/test/scala/cats/derived/show.scala @@ -1,21 +1,25 @@ -package cats.derived +package cats +package derived import cats.Show import cats.instances.all._ import shapeless.test.illTyped - -import MkShow._ import TestDefns._ class ShowTests extends KittensSuite { + + test("Simple case classes") { + implicit val sf = derive.show[Foo] val foo = Foo(42, Option("Hello")) val printedFoo = "Foo(i = 42, b = Some(Hello))" assert(foo.show == printedFoo) } - test("Nested case classes") { + test("Nested case classes auto derive inner class") { + implicit val so = derive.show[Outer] + val nested = Outer(Inner(3)) val printedNested = "Outer(in = Inner(i = 3))" @@ -23,6 +27,8 @@ class ShowTests extends KittensSuite { } test("Recursive ADTs with no type parameters") { + implicit val st = derive.show[IntTree] + val tree: IntTree = IntNode(IntLeaf(1), IntNode(IntNode(IntLeaf(2), IntLeaf(3)), IntLeaf(4))) val printedTree = "IntNode(l = IntLeaf(t = 1), r = IntNode(l = IntNode(l = IntLeaf(t = 2), r = IntLeaf(t = 3)), r = IntLeaf(t = 4)))" @@ -31,6 +37,7 @@ class ShowTests extends KittensSuite { } test("Non recursive ADTs with type parameters") { + implicit val sg = derive.show[GenericAdt[Int]] val genAdt: GenericAdt[Int] = GenericAdtCase(Some(1)) val printedGenAdt = "GenericAdtCase(v = Some(1))" @@ -38,6 +45,8 @@ class ShowTests extends KittensSuite { } test("Recursive ADTs with type parameters are not supported") { + import cats.derived.show._ + val tree: Tree[Int] = Node(Leaf(1), Node(Node(Leaf(2), Leaf(3)), Leaf(4))) val printedTree = "Node(l = Leaf(t = 1), r = Node(l = Node(l = Leaf(t = 2), r = Leaf(t = 3)), r = Leaf(t = 4)))" @@ -45,11 +54,4 @@ class ShowTests extends KittensSuite { illTyped("Show[Tree[Int]]") } - test("existing Show instances in scope are respected") { - implicit def showInt: Show[Foo] = new Show[Foo] { - def show(foo: Foo) = "" - } - - assert(Foo(42, Option("Hello")).show == "") - } } diff --git a/core/src/test/scala/cats/sequence/sequence.scala b/core/src/test/scala/cats/sequence/sequence.scala index 7ada3e8e..456386e6 100644 --- a/core/src/test/scala/cats/sequence/sequence.scala +++ b/core/src/test/scala/cats/sequence/sequence.scala @@ -118,6 +118,15 @@ class SequenceTests extends KittensSuite { } }) + test("sequence gen with different sort")(check { + forAll { (x: Option[Int], y: Option[String], z: Option[Float]) => + val myGen = sequenceGeneric[MyCase] + val expected = (x, y, z) mapN MyCase.apply + + myGen(b = y, a = x, c = z) == expected + } + }) + test("sequence gen for Either")(check { forAll { (x: Either[String, Int], y: Either[String, String], z: Either[String, Float]) => val myGen = sequenceGeneric[MyCase] diff --git a/extra-tests/src/test/scala/cats/derived/applicative.scala b/extra-tests/src/test/scala/cats/derived/applicative.scala deleted file mode 100644 index 0f859ce0..00000000 --- a/extra-tests/src/test/scala/cats/derived/applicative.scala +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2016 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package cats.derived -import cats.Applicative -import alleycats.Pure, alleycats.std.all._ -import cats.instances.int._ - -import TestDefns._ -import emptyk._, pure._, foldable._ , foldable.legacy._, functor._ , functor.legacy._, MkApply._, MkApplicative._ - -class ApplicativeTests extends KittensSuite { - - - test("Applicative[IList]") { - - val A = Applicative[IList] - - // some basic sanity checks - val lns = (1 to 10).toList - val ns = IList.fromSeq(lns) - val fPlusOne = IList.fromSeq(List((_: Int) + 1)) - - assert(A.ap(fPlusOne)(ns) === IList.fromSeq((2 to 11).toList)) - - } - -} - diff --git a/extra-tests/src/test/scala/cats/derived/apply.scala b/extra-tests/src/test/scala/cats/derived/apply.scala deleted file mode 100644 index add499f9..00000000 --- a/extra-tests/src/test/scala/cats/derived/apply.scala +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2016 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package cats.derived -import cats.{ Eq, Eval, Foldable, Functor, Apply}, Eval.now - -import alleycats.Pure, alleycats.std.all._ - -import cats.instances.int._ - -import foldable._ , foldable.legacy._ -import functor._ , functor.legacy._ -import TestDefns._ -import shapeless.Cached -import ApplyTests._ - -//import apply._ todo: export hook conflicts with functor - -class ApplyTests extends KittensSuite { - import emptyk._, pure._ - - import ApplyTests._ - - test("Apply[CaseClassWOption]") { - - val M = MkApply[CaseClassWOption] - val p1 = CaseClassWOption(Option(1)) - val f = CaseClassWOption(Option((_: Int) + 1)) - - assert(M.ap(f)(p1) == CaseClassWOption(Option(2))) - assert(M.ap(f)(CaseClassWOption(None)) == CaseClassWOption(None)) - val emptyF = CaseClassWOption[Int => Int](None) - assert(M.ap(emptyF)(CaseClassWOption(Option(1))) == CaseClassWOption(None)) - - } - - test("Apply[IList]") { - - val A = MkApply[IList] - - // some basic sanity checks - val lns = (1 to 10).toList - val ns = IList.fromSeq(lns) - val fPlusOne = IList.fromSeq(List((_: Int) + 1)) - - assert(A.ap(fPlusOne)(ns) === IList.fromSeq((2 to 11).toList)) - - - // more basic checks - val lnames = List("Aaron", "Betty", "Calvin", "Deirdre") - val names = IList.fromSeq(lnames) - val fLength = IList.fromSeq(List((_: String).length)) - val lengths = A.ap(fLength)(names) - - assert(lengths === IList.fromSeq(lnames.map(_.length))) - - // test trampolining - val llarge = 1 to 10000 - val large = IList.fromSeq(llarge) - val resultList = MkIterable[IList].iterable(A.ap(fPlusOne)(large)).toList - - assert(resultList === llarge.map(_ + 1)) - } - - test("Apply[λ[t => List[List[t]]]") { - - val A = MkApply[LList] - - val l = List(List(1), List(2, 3), List(4, 5, 6), List(), List(7)) - val expected = List(List(2), List(3, 4), List(5, 6, 7), List(), List(8)) - val fPlusOne: LList[Int => Int] = List(List((_: Int) + 1)) - - assert(A.ap(fPlusOne)(l) == expected) - } -} - -class ApplyWithoutEmptyKTests extends KittensSuite { - - - test("Apply[Tree]") { - val A = MkApply[Tree] - - val tree: Tree[String] = - Node( - Leaf("quux"), - Node( - Leaf("foo"), - Leaf("wibble") - ) - ) - - val expected: Tree[Int] = - Node( - Leaf(4), - Node( - Leaf(3), - Leaf(6) - ) - ) - val fLength: Tree[String => Int] = Leaf((_: String).length) - - assert(A.ap(fLength)(tree) == expected) - } - -} - - -object ApplyTests { - type LList[T] = List[List[T]] -} diff --git a/extra-tests/src/test/scala/cats/derived/monad.scala b/extra-tests/src/test/scala/cats/derived/monad.scala deleted file mode 100644 index 4fed1fc5..00000000 --- a/extra-tests/src/test/scala/cats/derived/monad.scala +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2015 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package cats.derived - -import cats.{Eval, Foldable}, Eval.now - -import alleycats.{EmptyK, ConsK, Pure}, alleycats.std.all._ - -import cats.instances.int._ - -import TestDefns._ - - -//import monad._ todo: importing causes compiler to hang -import shapeless.the - - - -class MonadTests extends KittensSuite { - - test("Monad[CaseClassWOption]") { - import emptyk._, pure._, foldable._, foldable.legacy._ - - val M = MkMonad[CaseClassWOption] - val p1 = M.pure(1) - val f = (i : Int) => M.pure(i + 1) - assert(M.flatMap(p1)(f) == CaseClassWOption(Option(2))) - - assert(M.flatMap(CaseClassWOption(None))(f) == CaseClassWOption(None)) - - } - - test("Monad[IList]") { - import emptyk._, pure._, consk.exports._, foldable._, foldable.legacy._ - - val A = MkMonad[IList] - - // some basic sanity checks - val lns = (1 to 10).toList - val ns = IList.fromSeq(lns) - val fPlusOne = (i: Int) => A.pure(i + 1) - - assert(A.flatMap(ns)(fPlusOne) === IList.fromSeq((2 to 11).toList)) - - - // more basic checks - val lnames = List("Aaron", "Betty", "Calvin", "Deirdre") - val names = IList.fromSeq(lnames) - val fLength = (s:String) => A.pure(s.length) - val lengths = A.flatMap(names)(fLength) - - assert(lengths === IList.fromSeq(lnames.map(_.length))) - - //trampoline - val llarge = 1 to 10000 - val large = IList.fromSeq(llarge) - val result = A.flatMap(large)(fPlusOne) - val resultList = MkIterable[IList].iterable(result).toList - assert(resultList === llarge.map(_+1)) - } - -}