Skip to content

Commit

Permalink
Merge branch 'master' into kleisli-id-instances
Browse files Browse the repository at this point in the history
  • Loading branch information
ceedubs committed Nov 12, 2015
2 parents fea2c94 + d50e1d4 commit 2992586
Show file tree
Hide file tree
Showing 11 changed files with 64 additions and 8 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ To get started with SBT, simply add the following to your `build.sbt`
file:

```scala
libraryDependencies += "org.spire-math" %% "cats" % "0.2.0"
libraryDependencies += "org.spire-math" %% "cats" % "0.3.0"
```

This will pull in all of Cats' modules. If you only require some
Expand All @@ -38,7 +38,7 @@ functionality, you can pick-and-choose from amongst these modules

Release notes for Cats are available in [CHANGES.md](CHANGES.md).

*Cats 0.2.0 is a pre-release: there are not currently source- or
*Cats 0.3.0 is a pre-release: there are not currently source- or
binary-compatibility guarantees.*

### Documentation
Expand Down
7 changes: 7 additions & 0 deletions core/src/main/scala/cats/data/Const.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package cats
package data

import cats.functor.Contravariant

/**
* [[Const]] is a phantom type, it does not contain a value of its second type parameter `B`
* [[Const]] can be seen as a type level version of `Function.const[A, B]: A => B => A`
Expand Down Expand Up @@ -46,6 +48,11 @@ private[data] sealed abstract class ConstInstances extends ConstInstances0 {
def show(f: Const[A, B]): String = f.show
}

implicit def constContravariant[C]: Contravariant[Const[C, ?]] = new Contravariant[Const[C, ?]] {
override def contramap[A, B](fa: Const[C, A])(f: (B) => A): Const[C, B] =
fa.retag[B]
}

implicit def constTraverse[C]: Traverse[Const[C, ?]] = new Traverse[Const[C, ?]] {
def traverse[G[_]: Applicative, A, B](fa: Const[C, A])(f: A => G[B]): G[Const[C, B]] =
fa.traverse(f)
Expand Down
8 changes: 7 additions & 1 deletion core/src/main/scala/cats/data/Kleisli.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package cats
package data

import cats.arrow.{Arrow, Choice, Split}
import cats.functor.Strong
import cats.functor.{Contravariant, Strong}

/**
* Represents a function `A => F[B]`.
Expand Down Expand Up @@ -114,6 +114,12 @@ private[data] sealed abstract class KleisliInstances extends KleisliInstances0 {

implicit def kleisliIdMonadReader[A]: MonadReader[Kleisli[Id, A, ?], A] =
kleisliMonadReader[Id, A]

implicit def kleisliContravariant[F[_], C]: Contravariant[Kleisli[F, ?, C]] =
new Contravariant[Kleisli[F, ?, C]] {
override def contramap[A, B](fa: Kleisli[F, A, C])(f: (B) => A): Kleisli[F, B, C] =
fa.lmap(f)
}
}

private[data] sealed abstract class KleisliInstances0 extends KleisliInstances1 {
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/scala/cats/data/OptionT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ final case class OptionT[F[_], A](value: F[Option[A]]) {
case None => F.pure(None)
})

def transform[B](f: Option[A] => Option[B])(implicit F: Functor[F]): OptionT[F, B] =
OptionT(F.map(value)(f))

def subflatMap[B](f: A => Option[B])(implicit F: Functor[F]): OptionT[F, B] =
transform(_.flatMap(f))

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

Expand Down
6 changes: 6 additions & 0 deletions core/src/main/scala/cats/data/XorT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ case class XorT[F[_], A, B](value: F[A Xor B]) {
def flatMapF[AA >: A, D](f: B => F[AA Xor D])(implicit F: Monad[F]): XorT[F, AA, D] =
flatMap(f andThen XorT.apply)

def transform[C, D](f: Xor[A, B] => Xor[C, D])(implicit F: Functor[F]): XorT[F, C, D] =
XorT(F.map(value)(f))

def subflatMap[AA >: A, D](f: B => AA Xor D)(implicit F: Functor[F]): XorT[F, AA, D] =
transform(_.flatMap(f))

def map[D](f: B => D)(implicit F: Functor[F]): XorT[F, A, D] = bimap(identity, f)

def leftMap[C](f: A => C)(implicit F: Functor[F]): XorT[F, C, B] = bimap(f, identity)
Expand Down
4 changes: 2 additions & 2 deletions docs/src/main/tut/const.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ The `const` function takes two arguments and simply returns the first argument,
final case class Const[A, B](getConst: A)
```

The `Const` data type takes two type parameters, but only ever stores a value of the first type paramter.
The `Const` data type takes two type parameters, but only ever stores a value of the first type parameter.
Because the second type parameter is not used in the data type, the type parameter is referred to as a
"phantom type".

Expand Down Expand Up @@ -247,7 +247,7 @@ implicit def constApplicative[Z : Monoid]: Applicative[Const[Z, ?]] =

We have our `Applicative`!

Going back to `Traverse`, we fill in the first paramter of `traverse` with `fa` since that's
Going back to `Traverse`, we fill in the first parameter of `traverse` with `fa` since that's
the only value that fits.

Now we need a `A => G[B]`. We have an `A => B`, and we've decided to use `Const` for our `G[_]`. We need to
Expand Down
2 changes: 1 addition & 1 deletion docs/src/site/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Cats is currently available for Scala 2.10 and 2.11.

To get started with SBT, simply add the following to your build.sbt file:

libraryDependencies += "org.spire-math" %% "cats" % "0.2.0"
libraryDependencies += "org.spire-math" %% "cats" % "0.3.0"

This will pull in all of Cats' modules. If you only require some
functionality, you can pick-and-choose from amongst these modules
Expand Down
6 changes: 5 additions & 1 deletion tests/src/test/scala/cats/tests/ConstTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ package tests
import algebra.laws.{GroupLaws, OrderLaws}

import cats.data.{Const, NonEmptyList}
import cats.laws.discipline.{ApplyTests, ApplicativeTests, SerializableTests, TraverseTests}
import cats.functor.Contravariant
import cats.laws.discipline._
import cats.laws.discipline.arbitrary.{constArbitrary, oneAndArbitrary}

class ConstTests extends CatsSuite {
Expand All @@ -31,4 +32,7 @@ class ConstTests extends CatsSuite {
checkAll("Const[Map[Int, Int], String]", OrderLaws[Const[Map[Int, Int], String]].eqv)
checkAll("PartialOrder[Const[Set[Int], String]]", OrderLaws[Const[Set[Int], String]].partialOrder)
checkAll("Order[Const[Int, String]]", OrderLaws[Const[Int, String]].order)

checkAll("Const[String, Int]", ContravariantTests[Const[String, ?]].contravariant[Int, Int, Int])
checkAll("Contravariant[Const[String, ?]]", SerializableTests.serializable(Contravariant[Const[String, ?]]))
}
5 changes: 4 additions & 1 deletion tests/src/test/scala/cats/tests/KleisliTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package tests

import cats.arrow.{Arrow, Choice, Split}
import cats.data.{Kleisli, Reader}
import cats.functor.Strong
import cats.functor.{Contravariant, Strong}
import cats.laws.discipline._
import cats.laws.discipline.arbitrary._
import cats.laws.discipline.eq._
Expand Down Expand Up @@ -93,6 +93,9 @@ class KleisliTests extends CatsSuite {
checkAll("SemigroupK[Lambda[A => Kleisli[Option, A, A]]]", SerializableTests.serializable(kleisliSemigroupK))
}

checkAll("Kleisli[Option, ?, Int]", ContravariantTests[Kleisli[Option, ?, Int]].contravariant[Int, Int, Int])
checkAll("Contravariant[Kleisli[Option, ?, Int]]", SerializableTests.serializable(Contravariant[Kleisli[Option, ?, Int]]))

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))
Expand Down
12 changes: 12 additions & 0 deletions tests/src/test/scala/cats/tests/OptionTTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,18 @@ class OptionTTests extends CatsSuite {
OptionT[Xor[String, ?], Int](xor).show should === ("Xor.Right(Some(1))")
}

test("transform consistent with value.map") {
forAll { (o: OptionT[List, Int], f: Option[Int] => Option[String]) =>
o.transform(f) should === (OptionT(o.value.map(f)))
}
}

test("subflatMap consistent with value.map+flatMap") {
forAll { (o: OptionT[List, Int], f: Int => Option[String]) =>
o.subflatMap(f) should === (OptionT(o.value.map(_.flatMap(f))))
}
}

checkAll("OptionT[List, Int]", MonadCombineTests[OptionT[List, ?]].monad[Int, Int, Int])
checkAll("MonadOptionT[List, ?]]", SerializableTests.serializable(Monad[OptionT[List, ?]]))

Expand Down
12 changes: 12 additions & 0 deletions tests/src/test/scala/cats/tests/XorTTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,16 @@ class XorTTests extends CatsSuite {
val xort = XorT.right[Id, String, Int](10)
xort.recoverWith { case "xort" => XorT.right[Id, String, Int](5) } should === (xort)
}

test("transform consistent with value.map") {
forAll { (xort: XorT[List, String, Int], f: String Xor Int => Long Xor Double) =>
xort.transform(f) should === (XorT(xort.value.map(f)))
}
}

test("subflatMap consistent with value.map+flatMap") {
forAll { (xort: XorT[List, String, Int], f: Int => String Xor Double) =>
xort.subflatMap(f) should === (XorT(xort.value.map(_.flatMap(f))))
}
}
}

0 comments on commit 2992586

Please sign in to comment.