From 557ba3630dbf4dd258829463c2855a81f148c5db Mon Sep 17 00:00:00 2001 From: Cody Allen Date: Tue, 15 Dec 2015 07:48:39 -0500 Subject: [PATCH 01/60] Remove unused Cokleisli.cokleisli method This method currently isn't used. Since `Cokleisli` is already a case class with an equivalent auto-generated `apply` method, I don't think I see the usefulness of it. Feel free to let me know if you would prefer to keep this around. --- core/src/main/scala/cats/data/Cokleisli.scala | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/core/src/main/scala/cats/data/Cokleisli.scala b/core/src/main/scala/cats/data/Cokleisli.scala index be6efbb76c..749cc2b42e 100644 --- a/core/src/main/scala/cats/data/Cokleisli.scala +++ b/core/src/main/scala/cats/data/Cokleisli.scala @@ -38,17 +38,11 @@ final case class Cokleisli[F[_], A, B](run: F[A] => B) { self => Cokleisli(fca => F.extract(F.map(fca)(_._1)) -> run(F.map(fca)(_._2))) } -object Cokleisli extends CokleisliInstances with CokleisliFunctions { +object Cokleisli extends CokleisliInstances { def pure[F[_], A, B](x: B): Cokleisli[F, A, B] = Cokleisli(_ => x) } -sealed trait CokleisliFunctions { - /** creates a [[Cokleisli]] from a function */ - def cokleisli[F[_], A, B](f: F[A] => B): Cokleisli[F, A, B] = - Cokleisli(f) -} - private[data] sealed abstract class CokleisliInstances extends CokleisliInstances0 { implicit def cokleisliArrow[F[_]](implicit ev: Comonad[F]): Arrow[Cokleisli[F, ?, ?]] = new CokleisliArrow[F] { def F: Comonad[F] = ev } From 1a3b46517bc19b50c5d84d9c2b18340222d2e236 Mon Sep 17 00:00:00 2001 From: Cody Allen Date: Tue, 15 Dec 2015 07:56:15 -0500 Subject: [PATCH 02/60] Check that Cokleisli contramapValue and lmap methods are consistent --- tests/src/test/scala/cats/tests/CokleisliTests.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/src/test/scala/cats/tests/CokleisliTests.scala b/tests/src/test/scala/cats/tests/CokleisliTests.scala index bdab63439c..a635e9b13e 100644 --- a/tests/src/test/scala/cats/tests/CokleisliTests.scala +++ b/tests/src/test/scala/cats/tests/CokleisliTests.scala @@ -70,4 +70,9 @@ class CokleisliTests extends SlowCatsSuite { } + test("contramapValue with Id consistent with lmap"){ + forAll { (c: Cokleisli[Id, Int, Long], f: Char => Int) => + c.contramapValue[Char](f) should === (c.lmap(f)) + } + } } From 34f38175971bbfc6bc3e0b5a15979258bb5eb63a Mon Sep 17 00:00:00 2001 From: Cody Allen Date: Tue, 15 Dec 2015 20:58:21 -0500 Subject: [PATCH 03/60] Minor cleanup to Coproduct Use `coflatMap` instead of `duplicate` to be consistent with `CoflatMap` and make CoproductComonad extends CoproductCoflatMap to reduce a couple duplicated methods. --- core/src/main/scala/cats/data/Coproduct.scala | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/core/src/main/scala/cats/data/Coproduct.scala b/core/src/main/scala/cats/data/Coproduct.scala index 1c4b8c64a0..e2b4a55ca8 100644 --- a/core/src/main/scala/cats/data/Coproduct.scala +++ b/core/src/main/scala/cats/data/Coproduct.scala @@ -18,7 +18,7 @@ final case class Coproduct[F[_], G[_], A](run: F[A] Xor G[A]) { run.bimap(a => F.coflatMap(a)(x => f(leftc(x))), a => G.coflatMap(a)(x => f(rightc(x)))) ) - def duplicate(implicit F: CoflatMap[F], G: CoflatMap[G]): Coproduct[F, G, Coproduct[F, G, A]] = + def coflatten(implicit F: CoflatMap[F], G: CoflatMap[G]): Coproduct[F, G, Coproduct[F, G, A]] = Coproduct(run.bimap( x => F.coflatMap(x)(a => leftc(a)) , x => G.coflatMap(x)(a => rightc(a))) @@ -195,23 +195,16 @@ private[data] trait CoproductCoflatMap[F[_], G[_]] extends CoflatMap[Coproduct[F def coflatMap[A, B](a: Coproduct[F, G, A])(f: Coproduct[F, G, A] => B): Coproduct[F, G, B] = a coflatMap f + override def coflatten[A](fa: Coproduct[F, G, A]): Coproduct[F, G, Coproduct[F, G, A]] = + fa.coflatten } -private[data] trait CoproductComonad[F[_], G[_]] extends Comonad[Coproduct[F, G, ?]] { +private[data] trait CoproductComonad[F[_], G[_]] extends Comonad[Coproduct[F, G, ?]] with CoproductCoflatMap[F, G] { implicit def F: Comonad[F] implicit def G: Comonad[G] - def map[A, B](a: Coproduct[F, G, A])(f: A => B): Coproduct[F, G, B] = - a map f - def extract[A](p: Coproduct[F, G, A]): A = p.extract - - def coflatMap[A, B](a: Coproduct[F, G, A])(f: Coproduct[F, G, A] => B): Coproduct[F, G, B] = - a coflatMap f - - def duplicate[A](a: Coproduct[F, G, A]): Coproduct[F, G, Coproduct[F, G, A]] = - a.duplicate } From 0596600185632e1bc04a563657bf6d0f3f83290c Mon Sep 17 00:00:00 2001 From: Alexey Levan Date: Wed, 16 Dec 2015 15:04:45 +0200 Subject: [PATCH 04/60] Fix typo in OptionT documentation --- docs/src/main/tut/optiont.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/tut/optiont.md b/docs/src/main/tut/optiont.md index ef751b3ad3..d97442a521 100644 --- a/docs/src/main/tut/optiont.md +++ b/docs/src/main/tut/optiont.md @@ -7,7 +7,7 @@ scaladoc: "#cats.data.OptionT" --- # OptionT -`OptionT[F[_], A` is a light wrapper on an `F[Option[A]]`. Speaking technically, it is a monad transformer for `Option`, but you don't need to know what that means for it to be useful. `OptionT` can be more convenient to work with than using `F[Option[A]]` directly. +`OptionT[F[_], A]` is a light wrapper on an `F[Option[A]]`. Speaking technically, it is a monad transformer for `Option`, but you don't need to know what that means for it to be useful. `OptionT` can be more convenient to work with than using `F[Option[A]]` directly. ## Reduce map boilerplate From 90f40b677c63bc9f15ecd73239e0d85a36f6e4ab Mon Sep 17 00:00:00 2001 From: Cody Allen Date: Wed, 16 Dec 2015 09:35:33 -0500 Subject: [PATCH 05/60] Add ScalaDocs for Option syntax --- core/src/main/scala/cats/syntax/option.scala | 158 ++++++++++++++++++- 1 file changed, 155 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala/cats/syntax/option.scala b/core/src/main/scala/cats/syntax/option.scala index c62f484e7b..81045b4cef 100644 --- a/core/src/main/scala/cats/syntax/option.scala +++ b/core/src/main/scala/cats/syntax/option.scala @@ -4,21 +4,173 @@ package syntax import cats.data.{ Xor, Validated, ValidatedNel } trait OptionSyntax { - def none[A] = Option.empty[A] - implicit def optionIdSyntax[A](a: A): OptionIdOps[A] = new OptionIdOps(a) - implicit def optionSyntax[A](oa: Option[A]): OptionOps[A] = new OptionOps(oa) + final def none[A] = Option.empty[A] + implicit final def optionIdSyntax[A](a: A): OptionIdOps[A] = new OptionIdOps(a) + implicit final def optionSyntax[A](oa: Option[A]): OptionOps[A] = new OptionOps(oa) } final class OptionIdOps[A](val a: A) extends AnyVal { + /** + * Wrap a value in `Some`. + * + * `3.some` is equivalent to `Some(3)`, but the former will have an inferred + * return type of `Option[Int]` while the latter will have `Some[Int]`. + * + * Example: + * {{{ + * scala> import cats.syntax.option._ + * scala> 3.some + * res0: Option[Int] = Some(3) + * }}} + */ def some: Option[A] = Option(a) } final class OptionOps[A](val oa: Option[A]) extends AnyVal { + /** + * If the `Option` is a `Some`, return its value in a [[cats.data.Xor.Left]]. + * If the `Option` is `None`, return the provided `B` value in a + * [[cats.data.Xor.Right]]. + * + * Example: + * {{{ + * scala> import cats.data.Xor + * scala> import cats.syntax.option._ + * + * scala> val error1: Option[String] = Some("error!") + * scala> error1.toLeftXor(3) + * res0: String Xor Int = Left(error!) + * + * scala> val error2: Option[String] = None + * scala> error2.toLeftXor(3) + * res1: String Xor Int = Right(3) + * }}} + */ def toLeftXor[B](b: => B): A Xor B = oa.fold[A Xor B](Xor.Right(b))(Xor.Left(_)) + + /** + * If the `Option` is a `Some`, return its value in a [[cats.data.Xor.Right]]. + * If the `Option` is `None`, return the provided `B` value in a + * [[cats.data.Xor.Left]]. + * + * Example: + * {{{ + * scala> import cats.data.Xor + * scala> import cats.syntax.option._ + * + * scala> val result1: Option[Int] = Some(3) + * scala> result1.toRightXor("error!") + * res0: String Xor Int = Right(3) + * + * scala> val result2: Option[Int] = None + * scala> result2.toRightXor("error!") + * res1: String Xor Int = Left(error!) + * }}} + */ def toRightXor[B](b: => B): B Xor A = oa.fold[B Xor A](Xor.Left(b))(Xor.Right(_)) + + /** + * If the `Option` is a `Some`, return its value in a [[cats.data.Validated.Invalid]]. + * If the `Option` is `None`, return the provided `B` value in a + * [[cats.data.Validated.Valid]]. + * + * Example: + * {{{ + * scala> import cats.data.Validated + * scala> import cats.syntax.option._ + * + * scala> val error1: Option[String] = Some("error!") + * scala> error1.toInvalid(3) + * res0: Validated[String, Int] = Invalid(error!) + * + * scala> val error2: Option[String] = None + * scala> error2.toInvalid(3) + * res1: Validated[String, Int] = Valid(3) + * }}} + */ def toInvalid[B](b: => B): Validated[A, B] = oa.fold[Validated[A, B]](Validated.Valid(b))(Validated.Invalid(_)) + + /** + * If the `Option` is a `Some`, wrap its value in a [[cats.data.NonEmptyList]] + * and return it in a [[cats.data.Validated.Invalid]]. + * If the `Option` is `None`, return the provided `B` value in a + * [[cats.data.Validated.Valid]]. + * + * Example: + * {{{ + * scala> import cats.data.ValidatedNel + * scala> import cats.syntax.option._ + * + * scala> val error1: Option[String] = Some("error!") + * scala> error1.toInvalidNel(3) + * res0: ValidatedNel[String, Int] = Invalid(OneAnd(error!,List())) + * + * scala> val error2: Option[String] = None + * scala> error2.toInvalidNel(3) + * res1: ValidatedNel[String, Int] = Valid(3) + * }}} + */ def toInvalidNel[B](b: => B): ValidatedNel[A, B] = oa.fold[ValidatedNel[A, B]](Validated.Valid(b))(Validated.invalidNel(_)) + + /** + * If the `Option` is a `Some`, return its value in a [[cats.data.Validated.Valid]]. + * If the `Option` is `None`, return the provided `B` value in a + * [[cats.data.Validated.Invalid]]. + * + * Example: + * {{{ + * scala> import cats.data.Validated + * scala> import cats.syntax.option._ + * + * scala> val result1: Option[Int] = Some(3) + * scala> result1.toValid("error!") + * res0: Validated[String, Int] = Valid(3) + * + * scala> val result2: Option[Int] = None + * scala> result2.toValid("error!") + * res1: Validated[String, Int] = Invalid(error!) + * }}} + */ def toValid[B](b: => B): Validated[B, A] = oa.fold[Validated[B, A]](Validated.Invalid(b))(Validated.Valid(_)) + + /** + * If the `Option` is a `Some`, return its value in a [[cats.data.Validated.Valid]]. + * If the `Option` is `None`, wrap the provided `B` value in a [[cats.data.NonEmptyList]] + * and return the result in a [[cats.data.Validated.Invalid]]. + * + * Example: + * {{{ + * scala> import cats.data.ValidatedNel + * scala> import cats.syntax.option._ + * + * scala> val result1: Option[Int] = Some(3) + * scala> result1.toValidNel("error!") + * res0: ValidatedNel[String, Int] = Valid(3) + * + * scala> val result2: Option[Int] = None + * scala> result2.toValidNel("error!") + * res1: ValidatedNel[String, Int] = Invalid(OneAnd(error!,List())) + * }}} + */ def toValidNel[B](b: => B): ValidatedNel[B, A] = oa.fold[ValidatedNel[B, A]](Validated.invalidNel(b))(Validated.Valid(_)) + + /** + * If the `Option` is a `Some`, return its value. If the `Option` is `None`, + * return the `empty` value for `Monoid[A]`. + * + * Example: + * {{{ + * scala> import cats.syntax.option._ + * scala> import cats.std.string._ + * + * scala> val someString: Option[String] = Some("hello") + * scala> someString.orEmpty + * res0: String = hello + * + * scala> val noneString: Option[String] = None + * scala> noneString.orEmpty + * res1: String = "" + * }}} + */ def orEmpty(implicit A: Monoid[A]): A = oa.getOrElse(A.empty) } From 1c8306cea3ccd60cb12cf6068d91bec59c166a66 Mon Sep 17 00:00:00 2001 From: Cody Allen Date: Thu, 17 Dec 2015 08:30:11 -0500 Subject: [PATCH 06/60] Add ScalaDoc for some FlatMap syntax --- core/src/main/scala/cats/syntax/flatMap.scala | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/core/src/main/scala/cats/syntax/flatMap.scala b/core/src/main/scala/cats/syntax/flatMap.scala index 7c8b278faa..a386f59108 100644 --- a/core/src/main/scala/cats/syntax/flatMap.scala +++ b/core/src/main/scala/cats/syntax/flatMap.scala @@ -19,7 +19,20 @@ trait FlatMapSyntax extends FlatMapSyntax1 { final class FlatMapOps[F[_], A](fa: F[A])(implicit F: FlatMap[F]) { def flatMap[B](f: A => F[B]): F[B] = F.flatMap(fa)(f) + + /** + * Pair `A` with the result of function application. + * + * Example: + * {{{ + * scala> import cats.std.list._ + * scala> import cats.syntax.flatMap._ + * scala> List("12", "34", "56").mproduct(_.toList) + * res0: List[(String, Char)] = List((12,1), (12,2), (34,3), (34,4), (56,5), (56,6)) + * }}} + */ def mproduct[B](f: A => F[B]): F[(A, B)] = F.mproduct(fa)(f) + def >>=[B](f: A => F[B]): F[B] = F.flatMap(fa)(f) /** Alias for [[followedBy]]. */ @@ -48,9 +61,43 @@ final class FlatMapOps[F[_], A](fa: F[A])(implicit F: FlatMap[F]) { } final class FlattenOps[F[_], A](ffa: F[F[A]])(implicit F: FlatMap[F]) { + + /** + * Flatten nested `F` values. + * + * Example: + * {{{ + * scala> import cats.data.Xor + * scala> import cats.syntax.flatMap._ + * scala> type ErrorOr[A] = String Xor A + * scala> val x: ErrorOr[ErrorOr[Int]] = Xor.right(Xor.right(3)) + * scala> x.flatten + * res0: ErrorOr[Int] = Right(3) + * }}} + */ def flatten: F[A] = F.flatten(ffa) } final class IfMOps[F[_]](fa: F[Boolean])(implicit F: FlatMap[F]) { + + /** + * A conditional lifted into the `F` context. + * + * Example: + * {{{ + * scala> import cats.{Eval, Now} + * scala> import cats.syntax.flatMap._ + * + * scala> val b1: Eval[Boolean] = Now(true) + * scala> val asInt1: Eval[Int] = b1.ifM(Now(1), Now(0)) + * scala> asInt1.value + * res0: Int = 1 + * + * scala> val b2: Eval[Boolean] = Now(false) + * scala> val asInt2: Eval[Int] = b2.ifM(Now(1), Now(0)) + * scala> asInt2.value + * res1: Int = 0 + * }}} + */ def ifM[B](ifTrue: => F[B], ifFalse: => F[B]): F[B] = F.ifM(fa)(ifTrue, ifFalse) } From fde1d19f56e1d0e53e2791c6455e91cb1689990e Mon Sep 17 00:00:00 2001 From: zaneli Date: Fri, 18 Dec 2015 16:29:32 +0900 Subject: [PATCH 07/60] Update crossScalaVersions --- .travis.yml | 2 +- build.sbt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0f2af9dd13..422b428603 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ git: depth: 9999 scala: -- 2.10.5 +- 2.10.6 - 2.11.7 cache: diff --git a/build.sbt b/build.sbt index f043cfffbb..06c2e26586 100644 --- a/build.sbt +++ b/build.sbt @@ -15,7 +15,7 @@ lazy val scoverageSettings = Seq( lazy val buildSettings = Seq( organization := "org.spire-math", scalaVersion := "2.11.7", - crossScalaVersions := Seq("2.10.5", "2.11.7") + crossScalaVersions := Seq("2.10.6", "2.11.7") ) lazy val catsDoctestSettings = Seq( From f619620217bbc722688435a331f1ec41ba3f79c8 Mon Sep 17 00:00:00 2001 From: Cody Allen Date: Fri, 18 Dec 2015 07:25:54 -0500 Subject: [PATCH 08/60] Remove Kleisli.function method in favor of Kleisli.apply --- core/src/main/scala/cats/data/Kleisli.scala | 7 ++----- core/src/main/scala/cats/data/package.scala | 2 +- tests/src/test/scala/cats/tests/KleisliTests.scala | 12 ++++++------ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/core/src/main/scala/cats/data/Kleisli.scala b/core/src/main/scala/cats/data/Kleisli.scala index a7bdcb6495..d04538eaeb 100644 --- a/core/src/main/scala/cats/data/Kleisli.scala +++ b/core/src/main/scala/cats/data/Kleisli.scala @@ -64,9 +64,6 @@ final case class Kleisli[F[_], A, B](run: A => F[B]) { self => object Kleisli extends KleisliInstances with KleisliFunctions private[data] sealed trait KleisliFunctions { - /** creates a [[Kleisli]] from a function */ - def function[F[_], A, B](f: A => F[B]): Kleisli[F, A, B] = - Kleisli(f) def pure[F[_], A, B](x: B)(implicit F: Applicative[F]): Kleisli[F, A, B] = Kleisli(_ => F.pure(x)) @@ -153,7 +150,7 @@ private[data] sealed abstract class KleisliInstances1 extends KleisliInstances2 fb.map(f) def product[B, C](fb: Kleisli[F, A, B], fc: Kleisli[F, A, C]): Kleisli[F, A, (B, C)] = - Kleisli.function(a => Applicative[F].product(fb.run(a), fc.run(a))) + Kleisli(a => Applicative[F].product(fb.run(a), fc.run(a))) } } @@ -163,7 +160,7 @@ private[data] sealed abstract class KleisliInstances2 extends KleisliInstances3 fa(f) def product[B, C](fb: Kleisli[F, A, B], fc: Kleisli[F, A, C]): Kleisli[F, A, (B, C)] = - Kleisli.function(a => Apply[F].product(fb.run(a), fc.run(a))) + Kleisli(a => Apply[F].product(fb.run(a), fc.run(a))) def map[B, C](fa: Kleisli[F, A, B])(f: B => C): Kleisli[F, A, C] = fa.map(f) diff --git a/core/src/main/scala/cats/data/package.scala b/core/src/main/scala/cats/data/package.scala index 65078b8fc2..1b8930c774 100644 --- a/core/src/main/scala/cats/data/package.scala +++ b/core/src/main/scala/cats/data/package.scala @@ -39,7 +39,7 @@ package object data { type Reader[A, B] = ReaderT[Id, A, B] object Reader { - def apply[A, B](f: A => B): Reader[A, B] = ReaderT.function[Id, A, B](f) + def apply[A, B](f: A => B): Reader[A, B] = ReaderT[Id, A, B](f) } type Writer[L, V] = WriterT[Id, L, V] diff --git a/tests/src/test/scala/cats/tests/KleisliTests.scala b/tests/src/test/scala/cats/tests/KleisliTests.scala index 6c86a28a0e..9c5f6cea22 100644 --- a/tests/src/test/scala/cats/tests/KleisliTests.scala +++ b/tests/src/test/scala/cats/tests/KleisliTests.scala @@ -103,7 +103,7 @@ class KleisliTests extends CatsSuite { test("local composes functions") { forAll { (f: Int => Option[String], g: Int => Int, i: Int) => - f(g(i)) should === (Kleisli.local[Option, String, Int](g)(Kleisli.function(f)).run(i)) + f(g(i)) should === (Kleisli.local[Option, String, Int](g)(Kleisli(f)).run(i)) } } @@ -114,26 +114,26 @@ class KleisliTests extends CatsSuite { } test("lift") { - val f = Kleisli.function { (x: Int) => (Some(x + 1): Option[Int]) } + val f = Kleisli { (x: Int) => (Some(x + 1): Option[Int]) } val l = f.lift[List] (List(1, 2, 3) >>= l.run) should === (List(Some(2), Some(3), Some(4))) } test("transform") { - val opt = Kleisli.function { (x: Int) => Option(x.toDouble) } + val opt = Kleisli { (x: Int) => Option(x.toDouble) } val optToList = new (Option ~> List) { def apply[A](fa: Option[A]): List[A] = fa.toList } val list = opt.transform(optToList) val is = 0.to(10).toList - is.map(list.run) should === (is.map(Kleisli.function { (x: Int) => List(x.toDouble) }.run)) + is.map(list.run) should === (is.map(Kleisli { (x: Int) => List(x.toDouble) }.run)) } test("local") { case class Config(i: Int, s: String) - val kint = Kleisli.function { (x: Int) => Option(x.toDouble) } + val kint = Kleisli { (x: Int) => Option(x.toDouble) } val kconfig1 = kint.local[Config](_.i) - val kconfig2 = Kleisli.function { (c: Config) => Option(c.i.toDouble) } + val kconfig2 = Kleisli { (c: Config) => Option(c.i.toDouble) } val config = Config(0, "cats") kconfig1.run(config) should === (kconfig2.run(config)) From 8b6e4aed2a1cde97f4bd243aba6932f4f96ae388 Mon Sep 17 00:00:00 2001 From: David Gregory Date: Fri, 18 Dec 2015 23:06:49 +0000 Subject: [PATCH 09/60] Move cats-free and cats-state in to cats-core --- build.sbt | 38 +++++-------------- .../src/main/scala/cats/free/Coyoneda.scala | 0 .../src/main/scala/cats/free/Free.scala | 0 .../scala/cats/free/FreeApplicative.scala | 0 .../src/main/scala/cats/free/Inject.scala | 0 .../src/main/scala/cats/free/Trampoline.scala | 0 .../src/main/scala/cats/free/Yoneda.scala | 0 .../src/main/scala/cats/free/package.scala | 0 .../src/main/scala/cats/state/StateT.scala | 0 .../src/main/scala/cats/state/package.scala | 0 .../scala/cats/tests}/CoyonedaTests.scala | 4 +- .../cats/tests}/FreeApplicativeTests.scala | 4 +- .../test/scala/cats/tests}/FreeTests.scala | 4 +- .../test/scala/cats/tests}/InjectTests.scala | 4 +- .../test/scala/cats/tests}/StateTTests.scala | 6 +-- .../scala/cats/tests}/WordCountTest.scala | 3 +- .../test/scala/cats/tests}/YonedaTests.scala | 4 +- 17 files changed, 23 insertions(+), 44 deletions(-) rename {free => core}/src/main/scala/cats/free/Coyoneda.scala (100%) rename {free => core}/src/main/scala/cats/free/Free.scala (100%) rename {free => core}/src/main/scala/cats/free/FreeApplicative.scala (100%) rename {free => core}/src/main/scala/cats/free/Inject.scala (100%) rename {free => core}/src/main/scala/cats/free/Trampoline.scala (100%) rename {free => core}/src/main/scala/cats/free/Yoneda.scala (100%) rename {free => core}/src/main/scala/cats/free/package.scala (100%) rename {state => core}/src/main/scala/cats/state/StateT.scala (100%) rename {state => core}/src/main/scala/cats/state/package.scala (100%) rename {free/src/test/scala/cats/free => tests/src/test/scala/cats/tests}/CoyonedaTests.scala (96%) rename {free/src/test/scala/cats/free => tests/src/test/scala/cats/tests}/FreeApplicativeTests.scala (98%) rename {free/src/test/scala/cats/free => tests/src/test/scala/cats/tests}/FreeTests.scala (98%) rename {free/src/test/scala/cats/free => tests/src/test/scala/cats/tests}/InjectTests.scala (98%) rename {state/src/test/scala/cats/state => tests/src/test/scala/cats/tests}/StateTTests.scala (97%) rename {state/src/test/scala/cats/state => tests/src/test/scala/cats/tests}/WordCountTest.scala (97%) rename {free/src/test/scala/cats/free => tests/src/test/scala/cats/tests}/YonedaTests.scala (95%) diff --git a/build.sbt b/build.sbt index f043cfffbb..bcfb76e8ca 100644 --- a/build.sbt +++ b/build.sbt @@ -62,7 +62,7 @@ lazy val disciplineDependencies = Seq( lazy val docSettings = Seq( autoAPIMappings := true, - unidocProjectFilter in (ScalaUnidoc, unidoc) := inProjects(coreJVM, freeJVM, stateJVM), + unidocProjectFilter in (ScalaUnidoc, unidoc) := inProjects(coreJVM), site.addMappingsToSiteDir(mappings in (ScalaUnidoc, packageDoc), "api"), site.addMappingsToSiteDir(tut, "_tut"), ghpagesNoJekyll := false, @@ -87,7 +87,7 @@ lazy val docs = project .settings(tutSettings) .settings(tutScalacOptions ~= (_.filterNot(Set("-Ywarn-unused-import", "-Ywarn-dead-code")))) .settings(commonJvmSettings) - .dependsOn(coreJVM, freeJVM, stateJVM) + .dependsOn(coreJVM) lazy val cats = project.in(file(".")) .settings(moduleName := "root") @@ -100,15 +100,15 @@ lazy val catsJVM = project.in(file(".catsJVM")) .settings(moduleName := "cats") .settings(catsSettings) .settings(commonJvmSettings) - .aggregate(macrosJVM, coreJVM, lawsJVM, freeJVM, stateJVM, testsJVM, jvm, docs, bench) - .dependsOn(macrosJVM, coreJVM, lawsJVM, freeJVM, stateJVM, testsJVM % "test-internal -> test", jvm, bench % "compile-internal;test-internal -> test") + .aggregate(macrosJVM, coreJVM, lawsJVM, testsJVM, jvm, docs, bench) + .dependsOn(macrosJVM, coreJVM, lawsJVM, testsJVM % "test-internal -> test", jvm, bench % "compile-internal;test-internal -> test") lazy val catsJS = project.in(file(".catsJS")) .settings(moduleName := "cats") .settings(catsSettings) .settings(commonJsSettings) - .aggregate(macrosJS, coreJS, lawsJS, freeJS, stateJS, testsJS, js) - .dependsOn(macrosJS, coreJS, lawsJS, freeJS, stateJS, testsJS % "test-internal -> test", js) + .aggregate(macrosJS, coreJS, lawsJS, testsJS, js) + .dependsOn(macrosJS, coreJS, lawsJS, testsJS % "test-internal -> test", js) .enablePlugins(ScalaJSPlugin) @@ -151,26 +151,6 @@ lazy val laws = crossProject.crossType(CrossType.Pure) lazy val lawsJVM = laws.jvm lazy val lawsJS = laws.js -lazy val free = crossProject.crossType(CrossType.Pure) - .dependsOn(macros, core, tests % "test-internal -> test") - .settings(moduleName := "cats-free") - .settings(catsSettings:_*) - .jsSettings(commonJsSettings:_*) - .jvmSettings(commonJvmSettings:_*) - -lazy val freeJVM = free.jvm -lazy val freeJS = free.js - -lazy val state = crossProject.crossType(CrossType.Pure) - .dependsOn(macros, core, free % "compile-internal;test-internal -> test", tests % "test-internal -> test") - .settings(moduleName := "cats-state") - .settings(catsSettings:_*) - .jsSettings(commonJsSettings:_*) - .jvmSettings(commonJvmSettings:_*) - -lazy val stateJVM = state.jvm -lazy val stateJS = state.js - lazy val tests = crossProject.crossType(CrossType.Pure) .dependsOn(macros, core, laws) .settings(moduleName := "cats-tests") @@ -194,7 +174,7 @@ lazy val jvm = project .settings(commonJvmSettings:_*) // bench is currently JVM-only -lazy val bench = project.dependsOn(macrosJVM, coreJVM, freeJVM, lawsJVM) +lazy val bench = project.dependsOn(macrosJVM, coreJVM, lawsJVM) .settings(moduleName := "cats-bench") .settings(catsSettings) .settings(noPublishSettings) @@ -227,11 +207,11 @@ lazy val publishSettings = Seq( ) ++ credentialSettings ++ sharedPublishSettings ++ sharedReleaseProcess // These aliases serialise the build for the benefit of Travis-CI. -addCommandAlias("buildJVM", ";macrosJVM/compile;coreJVM/compile;coreJVM/test;freeJVM/compile;freeJVM/test;stateJVM/compile;stateJVM/test;lawsJVM/compile;testsJVM/test;jvm/test;bench/test") +addCommandAlias("buildJVM", ";macrosJVM/compile;coreJVM/compile;coreJVM/test;lawsJVM/compile;testsJVM/test;jvm/test;bench/test") addCommandAlias("validateJVM", ";scalastyle;buildJVM;makeSite") -addCommandAlias("validateJS", ";macrosJS/compile;coreJS/compile;lawsJS/compile;testsJS/test;js/test;freeJS/compile;freeJS/test;stateJS/compile;stateJS/test") +addCommandAlias("validateJS", ";macrosJS/compile;coreJS/compile;lawsJS/compile;testsJS/test;js/test") addCommandAlias("validate", ";validateJS;validateJVM") diff --git a/free/src/main/scala/cats/free/Coyoneda.scala b/core/src/main/scala/cats/free/Coyoneda.scala similarity index 100% rename from free/src/main/scala/cats/free/Coyoneda.scala rename to core/src/main/scala/cats/free/Coyoneda.scala diff --git a/free/src/main/scala/cats/free/Free.scala b/core/src/main/scala/cats/free/Free.scala similarity index 100% rename from free/src/main/scala/cats/free/Free.scala rename to core/src/main/scala/cats/free/Free.scala diff --git a/free/src/main/scala/cats/free/FreeApplicative.scala b/core/src/main/scala/cats/free/FreeApplicative.scala similarity index 100% rename from free/src/main/scala/cats/free/FreeApplicative.scala rename to core/src/main/scala/cats/free/FreeApplicative.scala diff --git a/free/src/main/scala/cats/free/Inject.scala b/core/src/main/scala/cats/free/Inject.scala similarity index 100% rename from free/src/main/scala/cats/free/Inject.scala rename to core/src/main/scala/cats/free/Inject.scala diff --git a/free/src/main/scala/cats/free/Trampoline.scala b/core/src/main/scala/cats/free/Trampoline.scala similarity index 100% rename from free/src/main/scala/cats/free/Trampoline.scala rename to core/src/main/scala/cats/free/Trampoline.scala diff --git a/free/src/main/scala/cats/free/Yoneda.scala b/core/src/main/scala/cats/free/Yoneda.scala similarity index 100% rename from free/src/main/scala/cats/free/Yoneda.scala rename to core/src/main/scala/cats/free/Yoneda.scala diff --git a/free/src/main/scala/cats/free/package.scala b/core/src/main/scala/cats/free/package.scala similarity index 100% rename from free/src/main/scala/cats/free/package.scala rename to core/src/main/scala/cats/free/package.scala diff --git a/state/src/main/scala/cats/state/StateT.scala b/core/src/main/scala/cats/state/StateT.scala similarity index 100% rename from state/src/main/scala/cats/state/StateT.scala rename to core/src/main/scala/cats/state/StateT.scala diff --git a/state/src/main/scala/cats/state/package.scala b/core/src/main/scala/cats/state/package.scala similarity index 100% rename from state/src/main/scala/cats/state/package.scala rename to core/src/main/scala/cats/state/package.scala diff --git a/free/src/test/scala/cats/free/CoyonedaTests.scala b/tests/src/test/scala/cats/tests/CoyonedaTests.scala similarity index 96% rename from free/src/test/scala/cats/free/CoyonedaTests.scala rename to tests/src/test/scala/cats/tests/CoyonedaTests.scala index 942f904c47..26b517e22a 100644 --- a/free/src/test/scala/cats/free/CoyonedaTests.scala +++ b/tests/src/test/scala/cats/tests/CoyonedaTests.scala @@ -1,8 +1,8 @@ package cats -package free +package tests import cats.arrow.NaturalTransformation -import cats.tests.CatsSuite +import cats.free.Coyoneda import cats.laws.discipline.{FunctorTests, SerializableTests} import org.scalacheck.{Arbitrary, Gen} diff --git a/free/src/test/scala/cats/free/FreeApplicativeTests.scala b/tests/src/test/scala/cats/tests/FreeApplicativeTests.scala similarity index 98% rename from free/src/test/scala/cats/free/FreeApplicativeTests.scala rename to tests/src/test/scala/cats/tests/FreeApplicativeTests.scala index ca0e3fd77a..aae6fdf5ca 100644 --- a/free/src/test/scala/cats/free/FreeApplicativeTests.scala +++ b/tests/src/test/scala/cats/tests/FreeApplicativeTests.scala @@ -1,10 +1,10 @@ package cats -package free +package tests import cats.arrow.NaturalTransformation +import cats.free.FreeApplicative import cats.laws.discipline.{MonoidalTests, ApplicativeTests, SerializableTests} import cats.laws.discipline.eq.tuple3Eq -import cats.tests.CatsSuite import cats.data.Const import org.scalacheck.{Arbitrary, Gen} diff --git a/free/src/test/scala/cats/free/FreeTests.scala b/tests/src/test/scala/cats/tests/FreeTests.scala similarity index 98% rename from free/src/test/scala/cats/free/FreeTests.scala rename to tests/src/test/scala/cats/tests/FreeTests.scala index 9d9c88603c..96d58866f0 100644 --- a/free/src/test/scala/cats/free/FreeTests.scala +++ b/tests/src/test/scala/cats/tests/FreeTests.scala @@ -1,8 +1,8 @@ package cats -package free +package tests import cats.arrow.NaturalTransformation -import cats.tests.CatsSuite +import cats.free.{Free, Trampoline} import cats.laws.discipline.{MonoidalTests, MonadTests, SerializableTests} import cats.laws.discipline.eq._ import cats.laws.discipline.arbitrary.function0Arbitrary diff --git a/free/src/test/scala/cats/free/InjectTests.scala b/tests/src/test/scala/cats/tests/InjectTests.scala similarity index 98% rename from free/src/test/scala/cats/free/InjectTests.scala rename to tests/src/test/scala/cats/tests/InjectTests.scala index 0bd4ff45d0..54611ee836 100644 --- a/free/src/test/scala/cats/free/InjectTests.scala +++ b/tests/src/test/scala/cats/tests/InjectTests.scala @@ -1,9 +1,9 @@ package cats -package free +package tests import cats.data.{Xor, Coproduct} +import cats.free.{Free, Inject,:<:} import cats.laws.discipline.arbitrary -import cats.tests.CatsSuite import org.scalacheck._ class InjectTests extends CatsSuite { diff --git a/state/src/test/scala/cats/state/StateTTests.scala b/tests/src/test/scala/cats/tests/StateTTests.scala similarity index 97% rename from state/src/test/scala/cats/state/StateTTests.scala rename to tests/src/test/scala/cats/tests/StateTTests.scala index 06c646d1cc..51854b8e0d 100644 --- a/state/src/test/scala/cats/state/StateTTests.scala +++ b/tests/src/test/scala/cats/tests/StateTTests.scala @@ -1,9 +1,9 @@ package cats -package state +package tests -import cats.tests.CatsSuite import cats.laws.discipline.{MonoidalTests, MonadStateTests, MonoidKTests, SerializableTests} -import cats.free.FreeTests._ +import cats.state.{State, StateT} +import cats.tests.FreeTests._ import cats.laws.discipline.eq._ import org.scalacheck.{Arbitrary, Gen} diff --git a/state/src/test/scala/cats/state/WordCountTest.scala b/tests/src/test/scala/cats/tests/WordCountTest.scala similarity index 97% rename from state/src/test/scala/cats/state/WordCountTest.scala rename to tests/src/test/scala/cats/tests/WordCountTest.scala index 0f6b680dae..174a23329d 100644 --- a/state/src/test/scala/cats/state/WordCountTest.scala +++ b/tests/src/test/scala/cats/tests/WordCountTest.scala @@ -1,7 +1,6 @@ package cats -package state +package tests -import cats.tests.CatsSuite import cats.data.{ Func, AppFunc, Const } import Func.{ appFunc, appFuncU } diff --git a/free/src/test/scala/cats/free/YonedaTests.scala b/tests/src/test/scala/cats/tests/YonedaTests.scala similarity index 95% rename from free/src/test/scala/cats/free/YonedaTests.scala rename to tests/src/test/scala/cats/tests/YonedaTests.scala index 25886e2032..cdddda3fe4 100644 --- a/free/src/test/scala/cats/free/YonedaTests.scala +++ b/tests/src/test/scala/cats/tests/YonedaTests.scala @@ -1,7 +1,7 @@ package cats -package free +package tests -import cats.tests.CatsSuite +import cats.free.Yoneda import cats.laws.discipline.{FunctorTests, SerializableTests} import org.scalacheck.Arbitrary From 50a94c83e2f4da58a89e38a8a09774da2e04f238 Mon Sep 17 00:00:00 2001 From: David Gregory Date: Sat, 19 Dec 2015 00:32:38 +0000 Subject: [PATCH 10/60] Update `travis-publish.sh` removing `free` and `state` project commands --- scripts/travis-publish.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/travis-publish.sh b/scripts/travis-publish.sh index d74cdf0799..e1aab9727c 100755 --- a/scripts/travis-publish.sh +++ b/scripts/travis-publish.sh @@ -28,7 +28,7 @@ fi sbt_cmd="sbt ++$TRAVIS_SCALA_VERSION" coverage="$sbt_cmd coverage validateJVM coverageReport && bash <(curl -s https://codecov.io/bash)" -scala_js="$sbt_cmd macrosJS/compile coreJS/compile lawsJS/compile && $sbt_cmd testsJS/test && $sbt_cmd js/test && $sbt_cmd freeJS/test && $sbt_cmd stateJS/test" +scala_js="$sbt_cmd macrosJS/compile coreJS/compile lawsJS/compile && $sbt_cmd testsJS/test && $sbt_cmd js/test" scala_jvm="$sbt_cmd validateJVM" run_cmd="$coverage && $scala_js && $scala_jvm $publish_cmd" From 7ccce79da2987b44004337e0d1e354f64070dce7 Mon Sep 17 00:00:00 2001 From: "Frank S. Thomas" Date: Sun, 20 Dec 2015 17:16:11 +0100 Subject: [PATCH 11/60] Use SVG for badges --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ce98ffa3b1..f1b765f55a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Cats -[![Build Status](https://api.travis-ci.org/non/cats.png)](https://travis-ci.org/non/cats) -[![Workflow](https://badge.waffle.io/non/cats.png?label=ready&title=Ready)](https://waffle.io/non/cats) +[![Build Status](https://api.travis-ci.org/non/cats.svg)](https://travis-ci.org/non/cats) +[![Workflow](https://badge.waffle.io/non/cats.svg?label=ready&title=Ready)](https://waffle.io/non/cats) [![Chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/non/cats) [![codecov.io](http://codecov.io/github/non/cats/coverage.svg?branch=master)](http://codecov.io/github/non/cats?branch=master) [![Maven Central](https://img.shields.io/maven-central/v/org.spire-math/cats_2.11.svg)](https://maven-badges.herokuapp.com/maven-central/org.spire-math/cats_2.11) From 962fcab124eb204f0259e1bcf7a67723b9b7f2cf Mon Sep 17 00:00:00 2001 From: David Gregory Date: Mon, 21 Dec 2015 00:07:36 +0000 Subject: [PATCH 12/60] Remove reference to `free`, `state` modules in docs and fix broken links --- CONTRIBUTING.md | 2 +- README.md | 4 ---- docs/src/main/tut/const.md | 2 +- docs/src/main/tut/freemonad.md | 4 ++-- docs/src/main/tut/oneand.md | 2 +- docs/src/main/tut/optiont.md | 2 +- docs/src/main/tut/state.md | 2 +- docs/src/main/tut/streaming.md | 2 +- docs/src/main/tut/xor.md | 2 +- docs/src/site/index.md | 2 -- 10 files changed, 9 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5b557d7e9c..f36ea3a8e5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -115,7 +115,7 @@ Write about https://github.com/non/cats/pull/36#issuecomment-72892359 ### Write tests - Tests for cats-core go into the tests module, under the `cats.tests` package. -- Tests for additional modules, such as `free`, go into the tests directory within that module. +- Tests for additional modules, such as 'jvm', go into the tests directory within that module. - Cats tests should extend `CatsSuite`. `CatsSuite` integrates [ScalaTest](http://www.scalatest.org/) with [Discipline](https://github.com/typelevel/discipline) for law checking, and imports all syntax and standard instances for convenience. - The first parameter to the `checkAll` method provided by diff --git a/README.md b/README.md index ce98ffa3b1..cbf8ad7266 100644 --- a/README.md +++ b/README.md @@ -33,8 +33,6 @@ functionality, you can pick-and-choose from amongst these modules * `cats-macros`: Macros used by Cats syntax (*required*). * `cats-core`: Core type classes and functionality (*required*). * `cats-laws`: Laws for testing type class instances. - * `cats-free`: "Free" data constructors for various type classes. - * `cats-state`: Monad and transformer support for state. Release notes for Cats are available in [CHANGES.md](CHANGES.md). @@ -113,8 +111,6 @@ Initially Cats will support the following modules: * `macros`: Macro definitions needed for `core` and other projects. * `core`: Definitions for widely-used type classes and data types. * `laws`: The encoded laws for type classes, exported to assist third-party testing. - * `free`: "Free" data constructors for various type classes. - * `state`: Monad and transformer support for state. * `tests`: Verifies the laws, and runs any other tests. Not published. As the type class families grow, it's possible that additional modules diff --git a/docs/src/main/tut/const.md b/docs/src/main/tut/const.md index 32e4c075b9..7b443c206e 100644 --- a/docs/src/main/tut/const.md +++ b/docs/src/main/tut/const.md @@ -2,7 +2,7 @@ layout: default title: "Const" section: "data" -source: "https://github.com/non/cats/blob/master/data/src/main/scala/cats/data/Const.scala" +source: "https://github.com/non/cats/blob/master/core/src/main/scala/cats/data/Const.scala" scaladoc: "#cats.data.Const" --- # Const diff --git a/docs/src/main/tut/freemonad.md b/docs/src/main/tut/freemonad.md index 2cf3797f6e..94a3c9e9ff 100644 --- a/docs/src/main/tut/freemonad.md +++ b/docs/src/main/tut/freemonad.md @@ -2,8 +2,8 @@ layout: default title: "FreeMonads" section: "data" -source: "https://github.com/non/cats/blob/master/core/src/main/scala/cats/free/FreeMonad.scala" -scaladoc: "#cats.free.FreeMonad" +source: "https://github.com/non/cats/blob/master/core/src/main/scala/cats/free/Free.scala" +scaladoc: "#cats.free.Free" --- # Free Monad diff --git a/docs/src/main/tut/oneand.md b/docs/src/main/tut/oneand.md index d38cc4fab8..a70e36153f 100644 --- a/docs/src/main/tut/oneand.md +++ b/docs/src/main/tut/oneand.md @@ -2,7 +2,7 @@ layout: default title: "OneAnd" section: "data" -source: "https://github.com/non/cats/blob/master/data/src/main/scala/cats/data/OneAnd.scala" +source: "https://github.com/non/cats/blob/master/core/src/main/scala/cats/data/OneAnd.scala" scaladoc: "#cats.data.OneAnd" --- # OneAnd diff --git a/docs/src/main/tut/optiont.md b/docs/src/main/tut/optiont.md index d97442a521..1f0227993f 100644 --- a/docs/src/main/tut/optiont.md +++ b/docs/src/main/tut/optiont.md @@ -2,7 +2,7 @@ layout: default title: "OptionT" section: "data" -source: "https://github.com/non/cats/blob/master/data/src/main/scala/cats/data/optionT.scala" +source: "https://github.com/non/cats/blob/master/core/src/main/scala/cats/data/OptionT.scala" scaladoc: "#cats.data.OptionT" --- # OptionT diff --git a/docs/src/main/tut/state.md b/docs/src/main/tut/state.md index 7aa5414639..d7be7078bd 100644 --- a/docs/src/main/tut/state.md +++ b/docs/src/main/tut/state.md @@ -2,7 +2,7 @@ layout: default title: "State" section: "data" -source: "https://github.com/non/cats/blob/master/state/src/main/scala/cats/state/State.scala" +source: "https://github.com/non/cats/blob/master/core/src/main/scala/cats/state/StateT.scala" scaladoc: "#cats.state.StateT" --- # State diff --git a/docs/src/main/tut/streaming.md b/docs/src/main/tut/streaming.md index 4bbef0aee7..a5dde58d7f 100644 --- a/docs/src/main/tut/streaming.md +++ b/docs/src/main/tut/streaming.md @@ -2,7 +2,7 @@ layout: default title: "Streaming" section: "data" -source: "https://github.com/non/cats/blob/master/data/src/main/scala/cats/data/Streaming.scala" +source: "https://github.com/non/cats/blob/master/core/src/main/scala/cats/data/Streaming.scala" scaladoc: "#cats.data.Streaming" --- diff --git a/docs/src/main/tut/xor.md b/docs/src/main/tut/xor.md index 80b2099b6a..4abc3a3e75 100644 --- a/docs/src/main/tut/xor.md +++ b/docs/src/main/tut/xor.md @@ -2,7 +2,7 @@ layout: default title: "Xor" section: "data" -source: "https://github.com/non/cats/blob/master/data/src/main/scala/cats/data/Xor.scala" +source: "https://github.com/non/cats/blob/master/core/src/main/scala/cats/data/Xor.scala" scaladoc: "#cats.data.Xor" --- # Xor diff --git a/docs/src/site/index.md b/docs/src/site/index.md index 773a177f96..bafe7e0a9d 100644 --- a/docs/src/site/index.md +++ b/docs/src/site/index.md @@ -31,8 +31,6 @@ functionality, you can pick-and-choose from amongst these modules * `cats-macros`: Macros used by Cats syntax (*required*). * `cats-core`: Core type classes and functionality (*required*). * `cats-laws`: Laws for testing type class instances. - * `cats-free`: "Free" data constructors for various type classes. - * `cats-state`: Monad and transformer support for state. Release notes for Cats are available in [CHANGES.md](https://github.com/non/cats/blob/master/CHANGES.md). From d4dc4faf259e72263cb0ab5aac50a7233ec6b5e9 Mon Sep 17 00:00:00 2001 From: David Gregory Date: Tue, 22 Dec 2015 01:41:15 +0000 Subject: [PATCH 13/60] Improve stack consumption of `Eval.defer` --- core/src/main/scala/cats/Eval.scala | 18 ++++++++++++++++-- .../test/scala/cats/tests/FoldableTests.scala | 4 ++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/Eval.scala b/core/src/main/scala/cats/Eval.scala index 8512349092..93ec9297ee 100644 --- a/core/src/main/scala/cats/Eval.scala +++ b/core/src/main/scala/cats/Eval.scala @@ -222,8 +222,22 @@ object Eval extends EvalInstances { * they will be automatically created when needed. */ sealed abstract class Call[A](val thunk: () => Eval[A]) extends Eval[A] { - def memoize: Eval[A] = new Later(() => thunk().value) - def value: A = thunk().value + def memoize: Eval[A] = new Later(() => value) + def value: A = { + def loop(fa: Eval[A]): Eval[A] = fa match { + case call: Eval.Call[A] => + loop(call.thunk()) + case compute: Eval.Compute[A] => + new Eval.Compute[A] { + type Start = compute.Start + val start: () => Eval[Start] = () => compute.start() + val run: Start => Eval[A] = s => loop(compute.run(s)) + } + case other => other + } + + loop(this).value + } } /** diff --git a/tests/src/test/scala/cats/tests/FoldableTests.scala b/tests/src/test/scala/cats/tests/FoldableTests.scala index 2fb1eff709..1b0871755f 100644 --- a/tests/src/test/scala/cats/tests/FoldableTests.scala +++ b/tests/src/test/scala/cats/tests/FoldableTests.scala @@ -97,6 +97,10 @@ class FoldableTestsAdditional extends CatsSuite { } assert(result.value) + // test trampolining + val large = Stream((1 to 10000): _*) + assert(contains(large, 10000).value) + // toStreaming should be lazy assert(dangerous.toStreaming.take(3).toList == List(0, 1, 2)) } From 4a4fcb224a0bbff0cff9e3697114ec67b36c0fe5 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Tue, 22 Dec 2015 10:43:07 +0000 Subject: [PATCH 14/60] Fix a typo in NotNull --- core/src/main/scala/cats/NotNull.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/NotNull.scala b/core/src/main/scala/cats/NotNull.scala index 60ecf0ca6a..fba9975b59 100644 --- a/core/src/main/scala/cats/NotNull.scala +++ b/core/src/main/scala/cats/NotNull.scala @@ -18,7 +18,7 @@ object NotNull { private[this] def ambiguousException: Exception = new Exception("An instance of NotNull[Null] was used. This should never happen. Both ambiguous NotNull[Null] instances should always be in scope if one of them is.") - implicit def `If you are seeing this, you probably need to add an explicit type parameter somewhere, beause Null is being inferred.`: NotNull[Null] = throw ambiguousException + implicit def `If you are seeing this, you probably need to add an explicit type parameter somewhere, because Null is being inferred.`: NotNull[Null] = throw ambiguousException implicit def ambiguousNull2: NotNull[Null] = throw ambiguousException From 7bdf6f2d38a2dd321889656e28cbf363a1babcef Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Tue, 22 Dec 2015 10:43:26 +0000 Subject: [PATCH 15/60] Rewrite OptionT.flatMap in terms of flatMapF --- core/src/main/scala/cats/data/OptionT.scala | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/core/src/main/scala/cats/data/OptionT.scala b/core/src/main/scala/cats/data/OptionT.scala index 24972b49ab..df64e92a75 100644 --- a/core/src/main/scala/cats/data/OptionT.scala +++ b/core/src/main/scala/cats/data/OptionT.scala @@ -26,11 +26,7 @@ final case class OptionT[F[_], A](value: F[Option[A]]) { OptionT(F.map(value)(_.map(f))) def flatMap[B](f: A => OptionT[F, B])(implicit F: Monad[F]): OptionT[F, B] = - OptionT( - F.flatMap(value){ - case Some(a) => f(a).value - case None => F.pure(None) - }) + flatMapF(a => f(a).value) def flatMapF[B](f: A => F[Option[B]])(implicit F: Monad[F]): OptionT[F, B] = OptionT( From b07823fcdbb62098c66711b292d5c7b12807133b Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Wed, 23 Dec 2015 11:36:09 +0000 Subject: [PATCH 16/60] Dedup orElse/orElseF --- core/src/main/scala/cats/data/OptionT.scala | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/core/src/main/scala/cats/data/OptionT.scala b/core/src/main/scala/cats/data/OptionT.scala index df64e92a75..c91140d75e 100644 --- a/core/src/main/scala/cats/data/OptionT.scala +++ b/core/src/main/scala/cats/data/OptionT.scala @@ -72,11 +72,7 @@ final case class OptionT[F[_], A](value: F[Option[A]]) { F.map(value)(_.isEmpty) def orElse(default: => OptionT[F, A])(implicit F: Monad[F]): OptionT[F, A] = - OptionT( - F.flatMap(value) { - case s @ Some(_) => F.pure(s) - case None => default.value - }) + orElseF(default.value) def orElseF(default: => F[Option[A]])(implicit F: Monad[F]): OptionT[F, A] = OptionT( From 8d068f791bfc04f1b903ff0c10eff82a7978b8fb Mon Sep 17 00:00:00 2001 From: Arya Irani Date: Mon, 28 Dec 2015 20:46:18 -0500 Subject: [PATCH 17/60] add Reducible instance for OneAnd, deprecate Foldable instance --- core/src/main/scala/cats/data/OneAnd.scala | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/data/OneAnd.scala b/core/src/main/scala/cats/data/OneAnd.scala index 5500d15548..5564e818eb 100644 --- a/core/src/main/scala/cats/data/OneAnd.scala +++ b/core/src/main/scala/cats/data/OneAnd.scala @@ -106,8 +106,20 @@ private[data] sealed trait OneAndInstances extends OneAndLowPriority1 { implicit def oneAndSemigroup[F[_]: MonadCombine, A]: Semigroup[OneAnd[F, A]] = oneAndSemigroupK.algebra - implicit def oneAndFoldable[F[_]](implicit foldable: Foldable[F]): Foldable[OneAnd[F, ?]] = - new Foldable[OneAnd[F, ?]] { + @deprecated("use oneAndReducible", "0.4.0") + def oneAndFoldable[F[_]: Foldable]: Foldable[OneAnd[F, ?]] = oneAndReducible[F] + + implicit def oneAndReducible[F[_]](implicit F: Foldable[F]): Reducible[OneAnd[F, ?]] = + new Reducible[OneAnd[F, ?]] { + override def reduceLeftTo[A, B](fa: OneAnd[F, A])(f: (A) => B)(g: (B, A) => B): B = + F.foldLeft[A, B](fa.tail, f(fa.head))(g) + + override def reduceRightTo[A, B](fa: OneAnd[F, A])(f: (A) => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = + F.reduceRightToOption(fa.tail)(f)(g).flatMap { + case None => Eval.later(f(fa.head)) + case Some(b) => g(fa.head, Eval.now(b)) + } + override def foldLeft[A, B](fa: OneAnd[F, A], b: B)(f: (B, A) => B): B = fa.foldLeft(b)(f) override def foldRight[A, B](fa: OneAnd[F, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = From 9c1802eba4a12644a7a821e40d1c9b7bcbc9f67e Mon Sep 17 00:00:00 2001 From: Arya Irani Date: Tue, 29 Dec 2015 09:11:54 -0500 Subject: [PATCH 18/60] refactor oneAndReducible to use NonEmptyReducible --- core/src/main/scala/cats/data/OneAnd.scala | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/core/src/main/scala/cats/data/OneAnd.scala b/core/src/main/scala/cats/data/OneAnd.scala index 5564e818eb..8900f8fc59 100644 --- a/core/src/main/scala/cats/data/OneAnd.scala +++ b/core/src/main/scala/cats/data/OneAnd.scala @@ -110,21 +110,8 @@ private[data] sealed trait OneAndInstances extends OneAndLowPriority1 { def oneAndFoldable[F[_]: Foldable]: Foldable[OneAnd[F, ?]] = oneAndReducible[F] implicit def oneAndReducible[F[_]](implicit F: Foldable[F]): Reducible[OneAnd[F, ?]] = - new Reducible[OneAnd[F, ?]] { - override def reduceLeftTo[A, B](fa: OneAnd[F, A])(f: (A) => B)(g: (B, A) => B): B = - F.foldLeft[A, B](fa.tail, f(fa.head))(g) - - override def reduceRightTo[A, B](fa: OneAnd[F, A])(f: (A) => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = - F.reduceRightToOption(fa.tail)(f)(g).flatMap { - case None => Eval.later(f(fa.head)) - case Some(b) => g(fa.head, Eval.now(b)) - } - - override def foldLeft[A, B](fa: OneAnd[F, A], b: B)(f: (B, A) => B): B = - fa.foldLeft(b)(f) - override def foldRight[A, B](fa: OneAnd[F, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = - fa.foldRight(lb)(f) - override def isEmpty[A](fa: OneAnd[F, A]): Boolean = false + new NonEmptyReducible[OneAnd[F,?], F] { + override def split[A](fa: OneAnd[F,A]): (A, F[A]) = (fa.head, fa.tail) } implicit def oneAndMonad[F[_]](implicit monad: MonadCombine[F]): Monad[OneAnd[F, ?]] = From 8566afd663906b7716eccdcb09ce10e09529f177 Mon Sep 17 00:00:00 2001 From: Mike Curry Date: Sun, 3 Jan 2016 15:58:02 +0000 Subject: [PATCH 19/60] Adds Show[Vector] --- core/src/main/scala/cats/std/vector.scala | 6 ++++++ tests/src/test/scala/cats/tests/VectorTests.scala | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/core/src/main/scala/cats/std/vector.scala b/core/src/main/scala/cats/std/vector.scala index 9f88565c01..88d9797ceb 100644 --- a/core/src/main/scala/cats/std/vector.scala +++ b/core/src/main/scala/cats/std/vector.scala @@ -2,6 +2,7 @@ package cats package std import cats.data.Streaming +import cats.syntax.show._ trait VectorInstances { implicit val vectorInstance: Traverse[Vector] with MonadCombine[Vector] = @@ -43,6 +44,11 @@ trait VectorInstances { Streaming.fromVector(fa) } + implicit def vectorShow[A:Show]: Show[Vector[A]] = + new Show[Vector[A]] { + def show(fa: Vector[A]): String = fa.map(_.show).mkString("Vector(", ", ", ")") + } + // TODO: eventually use algebra's instances (which will deal with // implicit priority between Eq/PartialOrder/Order). diff --git a/tests/src/test/scala/cats/tests/VectorTests.scala b/tests/src/test/scala/cats/tests/VectorTests.scala index 3815b12369..423e101a15 100644 --- a/tests/src/test/scala/cats/tests/VectorTests.scala +++ b/tests/src/test/scala/cats/tests/VectorTests.scala @@ -13,4 +13,15 @@ class VectorTests extends CatsSuite { checkAll("Vector[Int] with Option", TraverseTests[Vector].traverse[Int, Int, Int, List[Int], Option, Option]) checkAll("Traverse[Vector]", SerializableTests.serializable(Traverse[Vector])) + + test("show") { + Vector(1, 2, 3).show should === ("Vector(1, 2, 3)") + + Vector.empty[Int].show should === ("Vector()") + + forAll { vec: Vector[String] => + vec.show should === (vec.toString) + } + } + } From 7e7ca849794f1404dc020b326867359bfcd43b75 Mon Sep 17 00:00:00 2001 From: Mike Curry Date: Sun, 3 Jan 2016 22:15:41 +0000 Subject: [PATCH 20/60] Adds Show[Stream] --- core/src/main/scala/cats/std/stream.scala | 6 +++++ .../test/scala/cats/tests/StreamTests.scala | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/core/src/main/scala/cats/std/stream.scala b/core/src/main/scala/cats/std/stream.scala index 988748b09d..3435e290fc 100644 --- a/core/src/main/scala/cats/std/stream.scala +++ b/core/src/main/scala/cats/std/stream.scala @@ -2,6 +2,7 @@ package cats package std import scala.collection.immutable.Stream.Empty +import cats.syntax.show._ trait StreamInstances { implicit val streamInstance: Traverse[Stream] with MonadCombine[Stream] with CoflatMap[Stream] = @@ -58,6 +59,11 @@ trait StreamInstances { override def isEmpty[A](fa: Stream[A]): Boolean = fa.isEmpty } + implicit def streamShow[A: Show]: Show[Stream[A]] = + new Show[Stream[A]] { + def show(fa: Stream[A]): String = if(fa.isEmpty) "Stream()" else s"Stream(${fa.head.show}, ?)" + } + // TODO: eventually use algebra's instances (which will deal with // implicit priority between Eq/PartialOrder/Order). diff --git a/tests/src/test/scala/cats/tests/StreamTests.scala b/tests/src/test/scala/cats/tests/StreamTests.scala index fa1080f06b..828fed2ddb 100644 --- a/tests/src/test/scala/cats/tests/StreamTests.scala +++ b/tests/src/test/scala/cats/tests/StreamTests.scala @@ -16,4 +16,26 @@ class StreamTests extends CatsSuite { checkAll("Stream[Int] with Option", TraverseTests[Stream].traverse[Int, Int, Int, List[Int], Option, Option]) checkAll("Traverse[Stream]", SerializableTests.serializable(Traverse[Stream])) + + test("show") { + Stream(1, 2, 3).show should === ("Stream(1, ?)") + Stream.empty[Int].show should === ("Stream()") + } + + test("Show[Stream] is referentially transparent, unlike Stream.toString") { + forAll { stream: Stream[Int] => + if (!stream.isEmpty) { + val unevaluatedStream = stream map identity + val initialShow = unevaluatedStream.show + + // Evaluating the tail can cause Stream.toString to return different values, + // depending on the internal state of the Stream. Show[Stream] should return + // consistent values independent of internal state. + unevaluatedStream.tail + initialShow should === (unevaluatedStream.show) + } else { + stream.show should === (stream.toString) + } + } + } } From 70200a93acb841d309d1e54278eeef8a1768421e Mon Sep 17 00:00:00 2001 From: Long Cao Date: Sun, 20 Dec 2015 22:04:55 -0600 Subject: [PATCH 21/60] rm dev jekyll config that wasn't working --- docs/src/site/_config.dev.yml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 docs/src/site/_config.dev.yml diff --git a/docs/src/site/_config.dev.yml b/docs/src/site/_config.dev.yml deleted file mode 100644 index 2af4066c1c..0000000000 --- a/docs/src/site/_config.dev.yml +++ /dev/null @@ -1,9 +0,0 @@ -name: Cats Documentation -markdown: redcarpet -highlighter: pygments -baseurl: / -apidocs: /api/ - -collections: - tut: - output: true From 70dadfbdac588cba0e3ca413b4bb3777d08a3dca Mon Sep 17 00:00:00 2001 From: Long Cao Date: Sun, 20 Dec 2015 22:05:24 -0600 Subject: [PATCH 22/60] fix docs baseurl to not have trailing slash, fixes duped url slashes --- docs/src/main/tut/xor.md | 2 +- docs/src/site/_config.yml | 2 +- docs/src/site/_layouts/default.html | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/src/main/tut/xor.md b/docs/src/main/tut/xor.md index 4abc3a3e75..00e0aa036a 100644 --- a/docs/src/main/tut/xor.md +++ b/docs/src/main/tut/xor.md @@ -39,7 +39,7 @@ How then do we communicate an error? By making it explicit in the data type we r ### `Xor` vs `Validated` -In general, `Validated` is used to accumulate errors, while `Xor` is used to short-circuit a computation upon the first error. For more information, see the `Validated` vs `Xor` section of the [`Validated` documentation]({{ baseurl }}/tut/validated.html). +In general, `Validated` is used to accumulate errors, while `Xor` is used to short-circuit a computation upon the first error. For more information, see the `Validated` vs `Xor` section of the [`Validated` documentation]({{ site.baseurl }}/tut/validated.html). ### Why not `Either` `Xor` is very similar to `scala.util.Either` - in fact, they are *isomorphic* (that is, diff --git a/docs/src/site/_config.yml b/docs/src/site/_config.yml index 657f4dbbf4..bc6d69ffea 100644 --- a/docs/src/site/_config.yml +++ b/docs/src/site/_config.yml @@ -1,7 +1,7 @@ name: Cats Documentation markdown: redcarpet highlighter: pygments -baseurl: /cats/ +baseurl: /cats apidocs: /cats/api/ collections: diff --git a/docs/src/site/_layouts/default.html b/docs/src/site/_layouts/default.html index 37b42cae59..d7b5608f8a 100644 --- a/docs/src/site/_layouts/default.html +++ b/docs/src/site/_layouts/default.html @@ -10,9 +10,9 @@ {{ site.name }} - {{ page.title }} - - - + + +