diff --git a/build.sbt b/build.sbt index c62cb5d6..ca94492a 100644 --- a/build.sbt +++ b/build.sbt @@ -21,13 +21,13 @@ lazy val commonSettings = Seq( "bintray/non" at "http://dl.bintray.com/non/maven" ), libraryDependencies ++= Seq( - "org.typelevel" %% "cats" % "0.7.2", - "org.typelevel" %% "alleycats-core" % "0.1.7", + "org.typelevel" %% "cats" % "0.8.1", + "org.typelevel" %% "alleycats-core" % "0.1.8", "com.chuusai" %% "shapeless" % "2.3.2", "org.typelevel" %% "export-hook" % "1.1.0", - "org.scalatest" %% "scalatest" % "3.0.0-M7" % "test", - "org.scalacheck" %% "scalacheck" % "1.12.5" % "test", - "org.typelevel" %% "discipline" % "0.4" % "test", + "org.scalatest" %% "scalatest" % "3.0.0" % "test", + "org.scalacheck" %% "scalacheck" % "1.13.4" % "test", + "org.typelevel" %% "discipline" % "0.7.2" % "test", compilerPlugin("com.milessabin" % "si2712fix-plugin" % "1.1.0" cross CrossVersion.full), compilerPlugin("org.spire-math" %% "kind-projector" % "0.6.3") diff --git a/core/src/main/scala/cats/derived/monad.scala b/core/src/main/scala/cats/derived/monad.scala index 28a23ea2..5e6eb5b6 100644 --- a/core/src/main/scala/cats/derived/monad.scala +++ b/core/src/main/scala/cats/derived/monad.scala @@ -19,14 +19,15 @@ object MkMonad extends MkMonad0 { def apply[F[_]](implicit mmf: MkMonad[F]): MkMonad[F] = mmf } -trait MkMonad0 extends MkMonad1 { + +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] { + ): 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] = { @@ -36,25 +37,36 @@ trait MkMonad0 extends MkMonad1 { }.value } - def tailRecM[A, B](a: A)(f: (A) => F[Either[A, B]]): F[B] = defaultTailRecM(a)(f) } } -trait MkMonad1 { +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] { + ): 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)) } - def tailRecM[A, B](a: A)(f: (A) => F[Either[A, B]]): F[B] = defaultTailRecM(a)(f) } + + + /** + * 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/test/scala/cats/derived/adtdefns.scala b/core/src/test/scala/cats/derived/adtdefns.scala index 700819b1..1fa10506 100644 --- a/core/src/test/scala/cats/derived/adtdefns.scala +++ b/core/src/test/scala/cats/derived/adtdefns.scala @@ -17,7 +17,7 @@ package cats.derived import cats.Eq -import org.scalacheck.Arbitrary, Arbitrary.arbitrary +import org.scalacheck.{Cogen, Arbitrary}, Arbitrary.arbitrary object TestDefns { sealed trait IList[A] @@ -27,11 +27,20 @@ object TestDefns { object IList { def fromSeq[T](ts: Seq[T]): IList[T] = ts.foldRight(INil[T](): IList[T])(ICons(_, _)) + + def toList[T](l: IList[T]): List[T] = l match { + case INil() => Nil + case ICons(h, t) => h :: toList(t) + } + } implicit def arbIList[A:Arbitrary]: Arbitrary[IList[A]] = Arbitrary( arbitrary[Seq[A]].map(IList.fromSeq)) + implicit def cogenIList[A:Cogen]: Cogen[IList[A]] = + Cogen[Seq[A]].contramap(IList.toList) + sealed trait Snoc[A] final case class SCons[A](init: Snoc[A], last: A) extends Snoc[A] final case class SNil[A]() extends Snoc[A] diff --git a/extra-tests/src/test/scala/cats/derived/monad.scala b/extra-tests/src/test/scala/cats/derived/monad.scala index 7baddc73..4fed1fc5 100644 --- a/extra-tests/src/test/scala/cats/derived/monad.scala +++ b/extra-tests/src/test/scala/cats/derived/monad.scala @@ -16,8 +16,6 @@ package cats.derived -import cats.data.Xor -import cats.laws.MonadLaws import cats.{Eval, Foldable}, Eval.now import alleycats.{EmptyK, ConsK, Pure}, alleycats.std.all._