Skip to content

Commit

Permalink
Merge branch 'master' of /~https://github.com/non/cats into monoidal-fu…
Browse files Browse the repository at this point in the history
…nctors
  • Loading branch information
julienrf committed Dec 8, 2015
2 parents ecd307e + 48286f2 commit 3058538
Show file tree
Hide file tree
Showing 45 changed files with 1,040 additions and 219 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ lazy val freeJVM = free.jvm
lazy val freeJS = free.js

lazy val state = crossProject.crossType(CrossType.Pure)
.dependsOn(macros, core, free, tests % "test-internal -> test")
.dependsOn(macros, core, free % "compile-internal;test-internal -> test", tests % "test-internal -> test")
.settings(moduleName := "cats-state")
.settings(catsSettings:_*)
.jsSettings(commonJsSettings:_*)
Expand Down
16 changes: 8 additions & 8 deletions core/src/main/scala/cats/arrow/NaturalTransformation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ trait NaturalTransformation[F[_], G[_]] extends Serializable { self =>

def andThen[H[_]](f: NaturalTransformation[G, H]): NaturalTransformation[F, H] =
f.compose(self)

def or[H[_]](h: H ~> G): Coproduct[F, H, ?] ~> G =
new (Coproduct[F, H, ?] ~> G) {
def apply[A](fa: Coproduct[F, H, A]): G[A] = fa.run match {
case Xor.Left(ff) => self(ff)
case Xor.Right(gg) => h(gg)
}
}
}

object NaturalTransformation {
def id[F[_]]: NaturalTransformation[F, F] =
new NaturalTransformation[F, F] {
def apply[A](fa: F[A]): F[A] = fa
}

def or[F[_], G[_], H[_]](f: F ~> H, g: G ~> H): Coproduct[F, G, ?] ~> H =
new (Coproduct[F, G, ?] ~> H) {
def apply[A](fa: Coproduct[F, G, A]): H[A] = fa.run match {
case Xor.Left(ff) => f(ff)
case Xor.Right(gg) => g(gg)
}
}
}
5 changes: 5 additions & 0 deletions core/src/main/scala/cats/data/Const.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ private[data] sealed abstract class ConstInstances extends ConstInstances0 {
}

private[data] sealed abstract class ConstInstances0 extends ConstInstances1 {

implicit def constSemigroup[A: Semigroup, B]: Semigroup[Const[A, B]] = new Semigroup[Const[A, B]] {
def combine(x: Const[A, B], y: Const[A, B]): Const[A, B] = x combine y
}

implicit def constPartialOrder[A: PartialOrder, B]: PartialOrder[Const[A, B]] = new PartialOrder[Const[A, B]]{
def partialCompare(x: Const[A, B], y: Const[A, B]): Double =
x partialCompare y
Expand Down
9 changes: 4 additions & 5 deletions core/src/main/scala/cats/data/OptionT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -137,19 +137,18 @@ private[data] sealed trait OptionTInstances1 {
}

private[data] sealed trait OptionTInstances extends OptionTInstances1 {
implicit def optionTMonadCombine[F[_]](implicit F: Monad[F]): MonadCombine[OptionT[F, ?]] =
new MonadCombine[OptionT[F, ?]] {

implicit def optionTMonad[F[_]](implicit F: Monad[F]): Monad[OptionT[F, ?]] =
new Monad[OptionT[F, ?]] {
def pure[A](a: A): OptionT[F, A] = OptionT.pure(a)

def flatMap[A, B](fa: OptionT[F, A])(f: A => OptionT[F, B]): OptionT[F, B] =
fa.flatMap(f)

override def map[A, B](fa: OptionT[F, A])(f: A => B): OptionT[F, B] =
fa.map(f)

override def empty[A]: OptionT[F,A] = OptionT(F.pure(None))
override def combine[A](x: OptionT[F,A], y: OptionT[F,A]): OptionT[F,A] = x orElse y
}

implicit def optionTEq[F[_], A](implicit FA: Eq[F[Option[A]]]): Eq[OptionT[F, A]] =
FA.on(_.value)

Expand Down
9 changes: 5 additions & 4 deletions core/src/main/scala/cats/data/StreamingT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -273,11 +273,12 @@ sealed abstract class StreamingT[F[_], A] extends Product with Serializable { lh
* This method will not force evaluation of any lazy part of a
* stream. As a result, you will see at most one element (the first
* one).
*
* Use .toString(n) to see the first n elements of the stream.
*/
override def toString: String =
"StreamingT(...)"
override def toString: String = this match {
case Cons(a, _) => s"StreamingT($a, ...)"
case Wait(_) => "StreamingT(...)"
case Empty() => "StreamingT()"
}
}

object StreamingT extends StreamingTInstances {
Expand Down
28 changes: 27 additions & 1 deletion core/src/main/scala/cats/data/Validated.scala
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,21 @@ sealed abstract class Validated[+E, +A] extends Product with Serializable {
case Valid(a) => f(a)
case i @ Invalid(_) => i
}

/**
* Combine this `Validated` with another `Validated`, using the `Semigroup`
* instances of the underlying `E` and `A` instances. The resultant `Validated`
* will be `Valid`, if, and only if, both this `Validated` instance and the
* supplied `Validated` instance are also `Valid`.
*/
def combine[EE >: E, AA >: A](that: Validated[EE, AA])(implicit EE: Semigroup[EE], AA: Semigroup[AA]): Validated[EE, AA] =
(this, that) match {
case (Valid(a), Valid(b)) => Valid(AA.combine(a, b))
case (Invalid(a), Invalid(b)) => Invalid(EE.combine(a, b))
case (Invalid(_), _) => this
case _ => that
}

}

object Validated extends ValidatedInstances with ValidatedFunctions{
Expand All @@ -187,6 +202,12 @@ object Validated extends ValidatedInstances with ValidatedFunctions{


private[data] sealed abstract class ValidatedInstances extends ValidatedInstances1 {

implicit def validatedMonoid[A, B](implicit A: Semigroup[A], B: Monoid[B]): Monoid[Validated[A, B]] = new Monoid[Validated[A, B]] {
def empty: Validated[A, B] = Valid(B.empty)
def combine(x: Validated[A, B], y: Validated[A, B]): Validated[A, B] = x combine y
}

implicit def validatedOrder[A: Order, B: Order]: Order[Validated[A,B]] = new Order[Validated[A,B]] {
def compare(x: Validated[A,B], y: Validated[A,B]): Int = x compare y
override def partialCompare(x: Validated[A,B], y: Validated[A,B]): Double = x partialCompare y
Expand Down Expand Up @@ -228,6 +249,12 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance
}

private[data] sealed abstract class ValidatedInstances1 extends ValidatedInstances2 {

implicit def validatedSemigroup[A, B](implicit A: Semigroup[A], B: Semigroup[B]): Semigroup[Validated[A, B]] =
new Semigroup[Validated[A, B]] {
def combine(x: Validated[A, B], y: Validated[A, B]): Validated[A, B] = x combine y
}

implicit def validatedPartialOrder[A: PartialOrder, B: PartialOrder]: PartialOrder[Validated[A,B]] =
new PartialOrder[Validated[A,B]] {
def partialCompare(x: Validated[A,B], y: Validated[A,B]): Double = x partialCompare y
Expand Down Expand Up @@ -295,4 +322,3 @@ trait ValidatedFunctions {
*/
def fromOption[A, B](o: Option[B], ifNone: => A): Validated[A,B] = o.fold(invalid[A, B](ifNone))(valid)
}

73 changes: 67 additions & 6 deletions core/src/main/scala/cats/data/WriterT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ private[data] sealed abstract class WriterTInstances extends WriterTInstances0 {
}

private[data] sealed abstract class WriterTInstances0 extends WriterTInstances1 {
implicit def writerTMonad[F[_], L](implicit F: Monad[F], L: Monoid[L]): Monad[WriterT[F, L, ?]] =
new WriterTMonad[F, L] {
implicit val F0: Monad[F] = F
implicit def writerTMonadCombine[F[_], L](implicit F: MonadCombine[F], L: Monoid[L]): MonadCombine[WriterT[F, L, ?]] =
new WriterTMonadCombine[F, L] {
implicit val F0: MonadCombine[F] = F
implicit val L0: Monoid[L] = L
}

Expand All @@ -82,29 +82,63 @@ private[data] sealed abstract class WriterTInstances0 extends WriterTInstances1
}

private[data] sealed abstract class WriterTInstances1 extends WriterTInstances2 {
implicit def writerTMonadFilter[F[_], L](implicit F: MonadFilter[F], L: Monoid[L]): MonadFilter[WriterT[F, L, ?]] =
new WriterTMonadFilter[F, L] {
implicit val F0: MonadFilter[F] = F
implicit val L0: Monoid[L] = L
}
}
private[data] sealed abstract class WriterTInstances2 extends WriterTInstances3 {
implicit def writerTMonad[F[_], L](implicit F: Monad[F], L: Monoid[L]): Monad[WriterT[F, L, ?]] =
new WriterTMonad[F, L] {
implicit val F0: Monad[F] = F
implicit val L0: Monoid[L] = L
}
}

private[data] sealed abstract class WriterTInstances3 extends WriterTInstances4 {
implicit def writerTAlternative[F[_], L](implicit F: Alternative[F], L: Monoid[L]): Alternative[WriterT[F, L, ?]] =
new WriterTAlternative[F, L] {
implicit val F0: Alternative[F] = F
implicit val L0: Monoid[L] = L
}
}

private[data] sealed abstract class WriterTInstances4 extends WriterTInstances5 {
implicit def writerTApplicative[F[_], L](implicit F: Applicative[F], L: Monoid[L]): Applicative[WriterT[F, L, ?]] =
new WriterTApplicative[F, L] {
implicit val F0: Applicative[F] = F
implicit val L0: Monoid[L] = L
}

implicit def writerTMonoidK[F[_], L](implicit F: MonoidK[F]): MonoidK[WriterT[F, L, ?]] =
new WriterTMonoidK[F, L] {
implicit val F0: MonoidK[F] = F
}
}
private[data] sealed abstract class WriterTInstances2 extends WriterTInstances3 {

private[data] sealed abstract class WriterTInstances5 extends WriterTInstances6 {
implicit def writerTFlatMap[F[_], L](implicit F: FlatMap[F], L: Semigroup[L]): FlatMap[WriterT[F, L, ?]] =
new WriterTFlatMap[F, L] {
implicit val F0: FlatMap[F] = F
implicit val L0: Semigroup[L] = L
}

implicit def writerTSemigroupK[F[_], L](implicit F: SemigroupK[F]): SemigroupK[WriterT[F, L, ?]] =
new WriterTSemigroupK[F, L] {
implicit val F0: SemigroupK[F] = F
}
}

private[data] sealed abstract class WriterTInstances3 extends WriterTInstances4 {
private[data] sealed abstract class WriterTInstances6 extends WriterTInstances7 {
implicit def writerTApply[F[_], L](implicit F: Apply[F], L: Semigroup[L]): Apply[WriterT[F, L, ?]] =
new WriterTApply[F, L] {
implicit val F0: Apply[F] = F
implicit val L0: Semigroup[L] = L
}
}

private[data] sealed abstract class WriterTInstances4 {
private[data] sealed abstract class WriterTInstances7 {
implicit def writerTFunctor[F[_], L](implicit F: Functor[F]): Functor[WriterT[F, L, ?]] = new WriterTFunctor[F, L] {
implicit val F0: Functor[F] = F
}
Expand Down Expand Up @@ -151,6 +185,33 @@ private[data] sealed trait WriterTMonad[F[_], L] extends WriterTApplicative[F, L
fa.flatMap(f)
}

private[data] sealed trait WriterTSemigroupK[F[_], L] extends SemigroupK[WriterT[F, L, ?]] {
implicit def F0: SemigroupK[F]

def combine[A](x: WriterT[F, L, A], y: WriterT[F, L, A]): WriterT[F, L, A] =
WriterT(F0.combine(x.run, y.run))
}

private[data] sealed trait WriterTMonoidK[F[_], L] extends MonoidK[WriterT[F, L, ?]] with WriterTSemigroupK[F, L] {
override implicit def F0: MonoidK[F]

def empty[A]: WriterT[F, L, A] = WriterT(F0.empty)
}

private[data] sealed trait WriterTAlternative[F[_], L] extends Alternative[WriterT[F, L, ?]] with WriterTMonoidK[F, L] with WriterTApplicative[F, L] {
override implicit def F0: Alternative[F]
}

private[data] sealed trait WriterTMonadFilter[F[_], L] extends MonadFilter[WriterT[F, L, ?]] with WriterTMonad[F, L] {
override implicit def F0: MonadFilter[F]

def empty[A]: WriterT[F, L, A] = WriterT(F0.empty)
}

private[data] sealed trait WriterTMonadCombine[F[_], L] extends MonadCombine[WriterT[F, L, ?]] with WriterTMonad[F, L] with WriterTAlternative[F, L] {
override implicit def F0: MonadCombine[F]
}

trait WriterTFunctions {
def putT[F[_], L, V](vf: F[V])(l: L)(implicit functorF: Functor[F]): WriterT[F, L, V] =
WriterT(functorF.map(vf)(v => (l, v)))
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/scala/cats/data/Xor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ private[data] sealed abstract class XorInstances extends XorInstances1 {
}

private[data] sealed abstract class XorInstances1 extends XorInstances2 {

implicit def xorSemigroup[A, B](implicit A: Semigroup[A], B: Semigroup[B]): Semigroup[A Xor B] =
new Semigroup[A Xor B] {
def combine(x: A Xor B, y: A Xor B): A Xor B = x combine y
}

implicit def xorPartialOrder[A: PartialOrder, B: PartialOrder]: PartialOrder[A Xor B] = new PartialOrder[A Xor B] {
def partialCompare(x: A Xor B, y: A Xor B): Double = x partialCompare y
override def eqv(x: A Xor B, y: A Xor B): Boolean = x === y
Expand Down
18 changes: 18 additions & 0 deletions core/src/main/scala/cats/data/XorT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,22 @@ final case class XorT[F[_], A, B](value: F[A Xor B]) {

def getOrElse[BB >: B](default: => BB)(implicit F: Functor[F]): F[BB] = F.map(value)(_.getOrElse(default))

def getOrElseF[BB >: B](default: => F[BB])(implicit F: Monad[F]): F[BB] = {
F.flatMap(value) {
case Xor.Left(_) => default
case Xor.Right(b) => F.pure(b)
}
}

def orElse[AA >: A, BB >: B](default: => XorT[F, AA, BB])(implicit F: Monad[F]): XorT[F, AA, BB] = {
XorT(F.flatMap(value) { xor =>
xor match {
case Xor.Left(_) => default.value
case _ => F.pure(xor)
}
})
}

def recover(pf: PartialFunction[A, B])(implicit F: Functor[F]): XorT[F, A, B] =
XorT(F.map(value)(_.recover(pf)))

Expand Down Expand Up @@ -277,10 +293,12 @@ private[data] trait XorTMonadFilter[F[_], L] extends MonadFilter[XorT[F, L, ?]]
def empty[A]: XorT[F, L, A] = XorT(F.pure(Xor.left(L.empty)))
}

/* TODO violates right absorbtion, right distributivity, and left distributivity -- re-enable when MonadCombine laws are split in to weak/strong
private[data] trait XorTMonadCombine[F[_], L] extends MonadCombine[XorT[F, L, ?]] with XorTMonadFilter[F, L] with XorTSemigroupK[F, L] {
implicit val F: Monad[F]
implicit val L: Monoid[L]
}
*/

private[data] sealed trait XorTFoldable[F[_], L] extends Foldable[XorT[F, L, ?]] {
implicit def F0: Foldable[F]
Expand Down
46 changes: 37 additions & 9 deletions core/src/main/scala/cats/std/function.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import cats.arrow.{Arrow, Choice}
import cats.data.Xor
import cats.functor.Contravariant

trait Function0Instances {
private[std] sealed trait Function0Instances {
implicit val function0Instance: Bimonad[Function0] =
new Bimonad[Function0] {
def extract[A](x: () => A): A = x()
Expand All @@ -26,7 +26,7 @@ trait Function0Instances {
}
}

trait Function1Instances {
private[std] sealed trait Function1Instances extends Function1Instances0 {
implicit def function1Contravariant[R]: Contravariant[? => R] =
new Contravariant[? => R] {
def contramap[T1, T0](fa: T1 => R)(f: T0 => T1): T0 => R =
Expand Down Expand Up @@ -71,13 +71,41 @@ trait Function1Instances {
def compose[A, B, C](f: B => C, g: A => B): A => C = f.compose(g)
}

implicit def function1Monoid[A,B](implicit B: Monoid[B]): Monoid[A => B] =
new Monoid[A => B] {
def empty: A => B = _ => B.empty
def combine(x: A => B, y: A => B): A => B = { a =>
B.combine(x(a), y(a))
}
}
implicit def function1Monoid[A,B](implicit M: Monoid[B]): Monoid[A => B] =
new Function1Monoid[A, B] { def B: Monoid[B] = M }

implicit val function1MonoidK: MonoidK[Lambda[A => A => A]] =
new Function1MonoidK {}
}

private[std] sealed trait Function1Instances0 {
implicit def function1Semigroup[A,B](implicit S: Semigroup[B]): Semigroup[A => B] =
new Function1Semigroup[A, B] { def B: Semigroup[B] = S }

implicit val function1SemigroupK: SemigroupK[Lambda[A => A => A]] =
new Function1SemigroupK {}
}

private[std] sealed trait Function1Semigroup[A, B] extends Semigroup[A => B] {
implicit def B: Semigroup[B]

override def combine(x: A => B, y: A => B): A => B = { a =>
B.combine(x(a), y(a))
}
}

private[std] sealed trait Function1Monoid[A, B] extends Monoid[A => B] with Function1Semigroup[A, B] {
implicit def B: Monoid[B]

override def empty: A => B = _ => B.empty
}

private[std] sealed trait Function1SemigroupK extends SemigroupK[Lambda[A => A => A]] {
override def combine[A](x: A => A, y: A => A): A => A = x compose y
}

private[std] sealed trait Function1MonoidK extends MonoidK[Lambda[A => A => A]] with Function1SemigroupK {
override def empty[A]: A => A = identity[A]
}

trait FunctionInstances
Expand Down
5 changes: 2 additions & 3 deletions docs/src/main/tut/apply.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ a context can be `Option`, `List` or `Future` for example).
However, the difference between `ap` and `map` is that for `ap` the function that
takes care of the transformation is of type `F[A => B]`, whereas for `map` it is `A => B`:

```tut
```tut:silent
import cats._
val intToString: Int => String = _.toString
val double: Int => Int = _ * 2
val addTwo: Int => Int = _ + 2
Expand Down Expand Up @@ -139,8 +140,6 @@ f2(Some(1), Some(2), Some(3))
All instances created by `|@|` have `map`, `ap`, and `tupled` methods of the appropriate arity:

```tut
import cats.syntax.monoidal._
val option2 = Option(1) |@| Option(2)
val option3 = option2 |@| Option.empty[Int]
Expand Down
Loading

0 comments on commit 3058538

Please sign in to comment.