Skip to content

Commit

Permalink
Merge branch 'master' into xort-traverse
Browse files Browse the repository at this point in the history
  • Loading branch information
ceedubs committed Nov 15, 2015
2 parents bab2733 + d0f9dba commit aa91f29
Show file tree
Hide file tree
Showing 18 changed files with 407 additions and 35 deletions.
6 changes: 3 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ lazy val commonSettings = Seq(
Resolver.sonatypeRepo("snapshots")
),
libraryDependencies ++= Seq(
"com.github.mpilquist" %%% "simulacrum" % "0.4.0",
"com.github.mpilquist" %%% "simulacrum" % "0.5.0",
"org.spire-math" %%% "algebra" % "0.3.1",
"org.spire-math" %%% "algebra-std" % "0.3.1",
"org.typelevel" %%% "machinist" % "0.4.1",
Expand Down Expand Up @@ -135,7 +135,7 @@ lazy val laws = crossProject.crossType(CrossType.Pure)
.settings(disciplineDependencies:_*)
.settings(libraryDependencies ++= Seq(
"org.spire-math" %%% "algebra-laws" % "0.3.1",
"com.github.inthenow" %%% "bricks-platform" % "0.0.1"))
"org.typelevel" %%% "catalysts-platform" % "0.0.2"))
.jsSettings(commonJsSettings:_*)
.jvmSettings(commonJvmSettings:_*)

Expand Down Expand Up @@ -170,7 +170,7 @@ lazy val tests = crossProject.crossType(CrossType.Pure)
.settings(noPublishSettings:_*)
.settings(libraryDependencies ++= Seq(
"org.scalatest" %%% "scalatest" % "3.0.0-M7" % "test",
"com.github.inthenow" %%% "bricks-platform" % "0.0.1" % "test"))
"org.typelevel" %%% "catalysts-platform" % "0.0.2" % "test"))
.jsSettings(commonJsSettings:_*)
.jvmSettings(commonJvmSettings:_*)

Expand Down
12 changes: 6 additions & 6 deletions core/src/main/scala/cats/data/Prod.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ object Prod extends ProdInstances {
Some((x.first, x.second))
}

private[data] sealed abstract class ProdInstances extends ProdInstance0 {
private[data] sealed abstract class ProdInstances extends ProdInstances0 {
implicit def prodAlternative[F[_], G[_]](implicit FF: Alternative[F], GG: Alternative[G]): Alternative[Lambda[X => Prod[F, G, X]]] = new ProdAlternative[F, G] {
def F: Alternative[F] = FF
def G: Alternative[G] = GG
Expand All @@ -33,35 +33,35 @@ private[data] sealed abstract class ProdInstances extends ProdInstance0 {
}
}

sealed abstract class ProdInstance0 extends ProdInstance1 {
sealed abstract class ProdInstances0 extends ProdInstances1 {
implicit def prodMonoidK[F[_], G[_]](implicit FF: MonoidK[F], GG: MonoidK[G]): MonoidK[Lambda[X => Prod[F, G, X]]] = new ProdMonoidK[F, G] {
def F: MonoidK[F] = FF
def G: MonoidK[G] = GG
}
}

sealed abstract class ProdInstance1 extends ProdInstance2 {
sealed abstract class ProdInstances1 extends ProdInstances2 {
implicit def prodSemigroupK[F[_], G[_]](implicit FF: SemigroupK[F], GG: SemigroupK[G]): SemigroupK[Lambda[X => Prod[F, G, X]]] = new ProdSemigroupK[F, G] {
def F: SemigroupK[F] = FF
def G: SemigroupK[G] = GG
}
}

sealed abstract class ProdInstance2 extends ProdInstance3 {
sealed abstract class ProdInstances2 extends ProdInstances3 {
implicit def prodApplicative[F[_], G[_]](implicit FF: Applicative[F], GG: Applicative[G]): Applicative[Lambda[X => Prod[F, G, X]]] = new ProdApplicative[F, G] {
def F: Applicative[F] = FF
def G: Applicative[G] = GG
}
}

sealed abstract class ProdInstance3 extends ProdInstance4 {
sealed abstract class ProdInstances3 extends ProdInstances4 {
implicit def prodApply[F[_], G[_]](implicit FF: Apply[F], GG: Apply[G]): Apply[Lambda[X => Prod[F, G, X]]] = new ProdApply[F, G] {
def F: Apply[F] = FF
def G: Apply[G] = GG
}
}

sealed abstract class ProdInstance4 {
sealed abstract class ProdInstances4 {
implicit def prodFunctor[F[_], G[_]](implicit FF: Functor[F], GG: Functor[G]): Functor[Lambda[X => Prod[F, G, X]]] = new ProdFunctor[F, G] {
def F: Functor[F] = FF
def G: Functor[G] = GG
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/data/Streaming.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ import scala.collection.mutable
* constructed with `Foldable#foldRight`, and that `.map` and
* `.flatMap` operations over the tail will be safely trampolined.
*/
sealed abstract class Streaming[A] { lhs =>
sealed abstract class Streaming[A] extends Product with Serializable { lhs =>

import Streaming.{Empty, Wait, Cons}

Expand Down Expand Up @@ -89,7 +89,7 @@ sealed abstract class Streaming[A] { lhs =>
/**
* A variant of fold, used for constructing streams.
*
* The only difference is that foldStream will preserve deferred
* The only difference is that foldStreaming will preserve deferred
* streams. This makes it more appropriate to use in situations
* where the stream's laziness must be preserved.
*/
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/data/StreamingT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import cats.syntax.all._
* not support many methods on `Streaming[A]` which return immediate
* values.
*/
sealed abstract class StreamingT[F[_], A] { lhs =>
sealed abstract class StreamingT[F[_], A] extends Product with Serializable { lhs =>

import StreamingT.{Empty, Wait, Cons}

Expand Down
103 changes: 95 additions & 8 deletions core/src/main/scala/cats/data/WriterT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ final case class WriterT[F[_], L, V](run: F[(L, V)]) {
def value(implicit functorF: Functor[F]): F[V] =
functorF.map(run)(_._2)

def ap[Z](f: WriterT[F, L, V => Z])(implicit F: Apply[F], L: Semigroup[L]): WriterT[F, L, Z] =
WriterT(
F.map2(f.run, run){
case ((l1, fvz), (l2, v)) => (L.combine(l1, l2), fvz(v))
})

def map[Z](fn: V => Z)(implicit functorF: Functor[F]): WriterT[F, L, Z] =
WriterT {
functorF.map(run) { z => (z._1, fn(z._2)) }
Expand Down Expand Up @@ -36,21 +42,102 @@ final case class WriterT[F[_], L, V](run: F[(L, V)]) {
}
object WriterT extends WriterTInstances with WriterTFunctions

private[data] sealed abstract class WriterTInstances {
implicit def writerTMonad[F[_], L](implicit monadF: Monad[F], monoidL: Monoid[L]): Monad[WriterT[F, L, ?]] = {
new Monad[WriterT[F, L, ?]] {
override def pure[A](a: A): WriterT[F, L, A] =
WriterT.value[F, L, A](a)
private[data] sealed abstract class WriterTInstances extends WriterTInstances0 {

implicit def writerTIdMonad[L:Monoid]: Monad[WriterT[Id, L, ?]] =
writerTMonad[Id, L]

override def flatMap[A, B](fa: WriterT[F, L, A])(f: A => WriterT[F, L, B]): WriterT[F, L, B] =
fa.flatMap(a => f(a))
// The Eq[(L, V)] can be derived from an Eq[L] and Eq[V], but we are waiting
// on an algebra release that includes https://github.com/non/algebra/pull/82
implicit def writerTIdEq[L, V](implicit E: Eq[(L, V)]): Eq[WriterT[Id, L, V]] =
writerTEq[Id, L, V]
}

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 val L0: Monoid[L] = L
}
}

implicit def writerTIdFunctor[L]: Functor[WriterT[Id, L, ?]] =
writerTFunctor[Id, L]

implicit def writerTIdFlatMap[L:Semigroup]: FlatMap[WriterT[Id, L, ?]] =
writerTFlatMap[Id, L]

implicit def writerTEq[F[_], L, V](implicit F: Eq[F[(L, V)]]): Eq[WriterT[F, L, V]] =
F.on(_.run)
}

private[data] sealed abstract class WriterTInstances1 extends WriterTInstances2 {
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
}
}
private[data] sealed abstract class WriterTInstances2 extends WriterTInstances3 {
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
}
}

private[data] sealed abstract class WriterTInstances3 extends WriterTInstances4 {
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 {
implicit def writerTFunctor[F[_], L](implicit F: Functor[F]): Functor[WriterT[F, L, ?]] = new WriterTFunctor[F, L] {
implicit val F0: Functor[F] = F
}
}

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

def map[A, B](fa: WriterT[F, L, A])(f: A => B): WriterT[F, L, B] =
fa.map(f)
}

private[data] sealed trait WriterTApply[F[_], L] extends WriterTFunctor[F, L] with Apply[WriterT[F, L, ?]] {
override implicit def F0: Apply[F]
implicit def L0: Semigroup[L]

def ap[A, B](fa: WriterT[F, L, A])(f: WriterT[F, L, A => B]): WriterT[F, L, B] =
fa ap f
}

private[data] sealed trait WriterTFlatMap[F[_], L] extends WriterTApply[F, L] with FlatMap[WriterT[F, L, ?]] {
override implicit def F0: FlatMap[F]
implicit def L0: Semigroup[L]

def flatMap[A, B](fa: WriterT[F, L, A])(f: A => WriterT[F, L, B]): WriterT[F, L, B] =
fa flatMap f
}

private[data] sealed trait WriterTApplicative[F[_], L] extends WriterTApply[F, L] with Applicative[WriterT[F, L, ?]] {
override implicit def F0: Applicative[F]
override implicit def L0: Monoid[L]

def pure[A](a: A): WriterT[F, L, A] =
WriterT.value[F, L, A](a)
}

private[data] sealed trait WriterTMonad[F[_], L] extends WriterTApplicative[F, L] with Monad[WriterT[F, L, ?]] {
override implicit def F0: Monad[F]
override implicit def L0: Monoid[L]

def flatMap[A, B](fa: WriterT[F, L, A])(f: A => WriterT[F, L, B]): WriterT[F, L, B] =
fa.flatMap(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
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/data/Xor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ trait XorFunctions {
* the resulting `Xor`. Uncaught exceptions are propagated.
*
* For example: {{{
* val result: NumberFormatException Xor Int = catching[NumberFormatException] { "foo".toInt }
* val result: NumberFormatException Xor Int = catchOnly[NumberFormatException] { "foo".toInt }
* }}}
*/
def catchOnly[T >: Null <: Throwable]: CatchOnlyPartiallyApplied[T] =
Expand Down
5 changes: 5 additions & 0 deletions core/src/main/scala/cats/syntax/bifunctor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,10 @@ trait BifunctorSyntax {
}

class BifunctorOps[F[_, _], A, B](fab: F[A, B])(implicit F: Bifunctor[F]) {

def bimap[C, D](f: A => C, g: B => D): F[C,D] = F.bimap(fab)(f,g)

def leftMap[C](f: A => C): F[C, B] = F.leftMap(fab)(f)

def rightMap[D](f: B => D): F[A, D] = F.rightMap(fab)(f)
}
15 changes: 15 additions & 0 deletions laws/src/main/scala/cats/laws/BifunctorLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@ trait BifunctorLaws[F[_, _]] {
def bifunctorComposition[A, B, C, X, Y, Z](fa: F[A, X], f: A => B, f2: B => C, g: X => Y, g2: Y => Z): IsEq[F[C, Z]] = {
fa.bimap(f, g).bimap(f2, g2) <-> fa.bimap(f andThen f2, g andThen g2)
}

def bifunctorLeftMapIdentity[A, B](fa: F[A, B]): IsEq[F[A, B]] =
fa.leftMap(identity) <-> fa

def bifunctorRightMapIdentity[A, B](fa: F[A, B]): IsEq[F[A, B]] =
fa.rightMap(identity) <-> fa

def bifunctorLeftMapComposition[A, B, C, D](fa: F[A, B], f: A => C, g: C => D): IsEq[F[D, B]] = {
fa.leftMap(f).leftMap(g) <-> fa.leftMap(f andThen g)
}

def bifunctorRightMapComposition[A, B, C, D](fa: F[A, B], f: B => C, g: C => D): IsEq[F[A, D]] = {
fa.rightMap(f).rightMap(g) <-> fa.rightMap(f andThen g)
}

}

object BifunctorLaws {
Expand Down
2 changes: 1 addition & 1 deletion laws/src/main/scala/cats/laws/SerializableLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package laws
import org.scalacheck.Prop
import org.scalacheck.Prop.{ False, Proof, Result }

import bricks.Platform
import catalysts.Platform

/**
* Check for Java Serializability.
Expand Down
11 changes: 8 additions & 3 deletions laws/src/main/scala/cats/laws/discipline/Arbitrary.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import org.scalacheck.Arbitrary.{arbitrary => getArbitrary}
/**
* Arbitrary instances for cats.data
*/
object arbitrary {
object arbitrary extends ArbitraryInstances0 {

implicit def constArbitrary[A, B](implicit A: Arbitrary[A]): Arbitrary[Const[A, B]] =
Arbitrary(A.arbitrary.map(Const[A, B]))
Expand Down Expand Up @@ -76,10 +76,15 @@ object arbitrary {
as <- Gen.listOf(A.arbitrary).map(_.take(8))
} yield StreamingT.fromList(as))

implicit def writerTArbitrary[F[_], L, V](implicit F: Arbitrary[F[(L, V)]]): Arbitrary[WriterT[F, L, V]] =
Arbitrary(F.arbitrary.map(WriterT(_)))
implicit def writerArbitrary[L:Arbitrary, V:Arbitrary]: Arbitrary[Writer[L, V]] =
writerTArbitrary[Id, L, V]

// until this is provided by scalacheck
implicit def partialFunctionArbitrary[A, B](implicit F: Arbitrary[A => Option[B]]): Arbitrary[PartialFunction[A, B]] =
Arbitrary(F.arbitrary.map(Function.unlift))
}

private[discipline] sealed trait ArbitraryInstances0 {
implicit def writerTArbitrary[F[_], L, V](implicit F: Arbitrary[F[(L, V)]]): Arbitrary[WriterT[F, L, V]] =
Arbitrary(F.arbitrary.map(WriterT(_)))
}
10 changes: 8 additions & 2 deletions laws/src/main/scala/cats/laws/discipline/BifunctorTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,19 @@ trait BifunctorTests[F[_, _]] extends Laws {
ArbB2: Arbitrary[B => B2],
ArbB3: Arbitrary[B2 => B3],
EqFAB: Eq[F[A, B]],
EqFCZ: Eq[F[A3, B3]]
EqFCZ: Eq[F[A3, B3]],
EqFA3B: Eq[F[A3, B]],
EqFAB3: Eq[F[A, B3]]
): RuleSet = {
new DefaultRuleSet(
name = "Bifunctor",
parent = None,
"Bifunctor Identity" -> forAll(laws.bifunctorIdentity[A, B] _),
"Bifunctor associativity" -> forAll(laws.bifunctorComposition[A, A2, A3, B, B2, B3] _)
"Bifunctor associativity" -> forAll(laws.bifunctorComposition[A, A2, A3, B, B2, B3] _),
"Bifunctor leftMap Identity" -> forAll(laws.bifunctorLeftMapIdentity[A, B] _),
"Bifunctor rightMap Identity" -> forAll(laws.bifunctorRightMapIdentity[A, B] _),
"Bifunctor leftMap associativity" -> forAll(laws.bifunctorLeftMapComposition[A, B, A2, A3] _),
"Bifunctor rightMap associativity" -> forAll(laws.bifunctorRightMapComposition[A, B, B2, B3] _)
)
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/src/test/scala/cats/tests/CatsSuite.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cats
package tests

import bricks.Platform
import catalysts.Platform

import cats.std.AllInstances
import cats.syntax.{AllSyntax, EqOps}
Expand Down
12 changes: 12 additions & 0 deletions tests/src/test/scala/cats/tests/IorTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,16 @@ class IorTests extends CatsSuite {
iorMaybe should === (Some(ior))
}
}

test("to consistent with toList") {
forAll { (x: Int Ior String) =>
x.to[List, String] should === (x.toList)
}
}

test("to consistent with toOption") {
forAll { (x: Int Ior String) =>
x.to[Option, String] should === (x.toOption)
}
}
}
8 changes: 8 additions & 0 deletions tests/src/test/scala/cats/tests/MapTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,12 @@ class MapTests extends CatsSuite {

checkAll("Map[Int, Int] with Option", TraverseTests[Map[Int, ?]].traverse[Int, Int, Int, Int, Option, Option])
checkAll("Traverse[Map[Int, ?]]", SerializableTests.serializable(Traverse[Map[Int, ?]]))

test("show isn't empty and is formatted as expected") {
forAll { (map: Map[Int, String]) =>
map.show.nonEmpty should === (true)
map.show.startsWith("Map(") should === (true)
map.show should === (implicitly[Show[Map[Int, String]]].show(map))
}
}
}
Loading

0 comments on commit aa91f29

Please sign in to comment.