Skip to content

Commit

Permalink
Merge branch 'master' into contravariant-show
Browse files Browse the repository at this point in the history
  • Loading branch information
edmundnoble authored May 5, 2017
2 parents e96bb75 + 404f348 commit 17bf536
Show file tree
Hide file tree
Showing 50 changed files with 508 additions and 469 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ There are many projects that integrate with Cats:
* [Dogs](https://github.com/stew/dogs): pure functional collections and data structures.
* [Fetch](https://github.com/47deg/fetch): efficient data access to heterogeneous data sources.
* [Frameless](https://github.com/adelbertc/frameless): Expressive types for Spark.
* [Freestyle](https://github.com/47deg/freestyle): pure functional framework for Free and Tagless Final apps & libs.
* [FS2](https://github.com/functional-streams-for-scala): compositional, streaming I/O library
* [Kittens](https://github.com/milessabin/kittens): automatically derived type class instances.
* [Monix](https://github.com/monixio/monix): high-performance library for composing asynchronous and event-based programs.
Expand Down
10 changes: 6 additions & 4 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ lazy val commonSettings = Seq(
Resolver.sonatypeRepo("snapshots")
),
libraryDependencies ++= Seq(
"com.github.mpilquist" %%% "simulacrum" % "0.10.0",
"com.github.mpilquist" %%% "simulacrum" % "0.10.0" % "compile-time",
"org.typelevel" %%% "machinist" % "0.6.1",
compilerPlugin("org.scalamacros" %% "paradise" % "2.1.0" cross CrossVersion.patch),
compilerPlugin("org.spire-math" %% "kind-projector" % "0.9.3")
Expand All @@ -45,7 +45,9 @@ lazy val commonSettings = Seq(
parallelExecution in Test := false,
scalacOptions in (Compile, doc) := (scalacOptions in (Compile, doc)).value.filter(_ != "-Xfatal-warnings"),
// workaround for https://github.com/scalastyle/scalastyle-sbt-plugin/issues/47
scalastyleSources in Compile ++= (unmanagedSourceDirectories in Compile).value
scalastyleSources in Compile ++= (unmanagedSourceDirectories in Compile).value,
ivyConfigurations += config("compile-time").hide,
unmanagedClasspath in Compile ++= update.value.select(configurationFilter("compile-time"))
) ++ warnUnusedImport ++ update2_12

lazy val tagName = Def.setting{
Expand Down Expand Up @@ -91,8 +93,8 @@ lazy val includeGeneratedSrc: Setting[_] = {
lazy val catsSettings = commonSettings ++ publishSettings ++ scoverageSettings ++ javadocSettings

lazy val scalaCheckVersion = "1.13.4"
lazy val scalaTestVersion = "3.0.0"
lazy val disciplineVersion = "0.7.2"
lazy val scalaTestVersion = "3.0.1"
lazy val disciplineVersion = "0.7.3"

lazy val disciplineDependencies = Seq(
libraryDependencies += "org.scalacheck" %%% "scalacheck" % scalaCheckVersion,
Expand Down
45 changes: 0 additions & 45 deletions core/src/main/scala/cats/Foldable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -231,30 +231,6 @@ import simulacrum.typeclass
G.map2Eval(f(a), acc) { (_, _) => () }
}.value

/**
* Behaves like traverse_, but uses [[Unapply]] to find the
* [[Applicative]] instance for `G` - used when `G` is a
* type constructor with two or more parameters such as [[scala.util.Either]]
*
* {{{
* scala> import cats.implicits._
* scala> def parseInt(s: String): Either[String, Int] =
* | try { Right(s.toInt) }
* | catch { case _: NumberFormatException => Left("boo") }
* scala> val F = Foldable[List]
* scala> F.traverseU_(List("333", "444"))(parseInt)
* res0: Either[String, Unit] = Right(())
* scala> F.traverseU_(List("333", "zzz"))(parseInt)
* res1: Either[String, Unit] = Left(boo)
* }}}
*
* Note that using `traverse_` instead of `traverseU_` would not compile without
* explicitly passing in the type parameters - the type checker has trouble
* inferring the appropriate instance.
*/
def traverseU_[A, GB](fa: F[A])(f: A => GB)(implicit U: Unapply[Applicative, GB]): U.M[Unit] =
traverse_(fa)(f.andThen(U.subst))(U.TC)

/**
* Sequence `F[G[A]]` using `Applicative[G]`.
*
Expand All @@ -275,27 +251,6 @@ import simulacrum.typeclass
def sequence_[G[_]: Applicative, A](fga: F[G[A]]): G[Unit] =
traverse_(fga)(identity)

/**
* Behaves like sequence_, but uses [[Unapply]] to find the
* [[Applicative]] instance for `G` - used when `G` is a
* type constructor with two or more parameters such as [[scala.util.Either]]
*
* {{{
* scala> import cats.implicits._
* scala> val F = Foldable[List]
* scala> F.sequenceU_(List(Either.right[String, Int](333), Right(444)))
* res0: Either[String, Unit] = Right(())
* scala> F.sequenceU_(List(Either.right[String, Int](333), Left("boo")))
* res1: Either[String, Unit] = Left(boo)
* }}}
*
* Note that using `sequence_` instead of `sequenceU_` would not compile without
* explicitly passing in the type parameters - the type checker has trouble
* inferring the appropriate instance.
*/
def sequenceU_[GA](fa: F[GA])(implicit U: Unapply[Applicative, GA]): U.M[Unit] =
traverseU_(fa)(identity)

/**
* Fold implemented using the given `MonoidK[G]` instance.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import cats.arrow.FunctionK
import cats.data.EitherK

/**
* Inject type class as described in "Data types a la carte" (Swierstra 2008).
* The injection type class as described in "Data types a la carte"
* (Swierstra 2008).
*
* @see [[http://www.staff.science.uu.nl/~swier004/publications/2008-jfp.pdf]]
*/
sealed abstract class Inject[F[_], G[_]] {
sealed abstract class InjectK[F[_], G[_]] {
def inj: FunctionK[F, G]

def prj: FunctionK[G, λ[α => Option[F[α]]]]
Expand All @@ -18,29 +19,29 @@ sealed abstract class Inject[F[_], G[_]] {
def unapply[A](ga: G[A]): Option[F[A]] = prj(ga)
}

private[cats] sealed abstract class InjectInstances {
implicit def catsReflexiveInjectInstance[F[_]]: Inject[F, F] =
new Inject[F, F] {
val inj = λ[FunctionK[F, F]](identity(_))
private[cats] sealed abstract class InjectKInstances {
implicit def catsReflexiveInjectKInstance[F[_]]: InjectK[F, F] =
new InjectK[F, F] {
val inj = FunctionK.id[F]

val prj = λ[FunctionK[F, λ[α => Option[F[α]]]]](Some(_))
}

implicit def catsLeftInjectInstance[F[_], G[_]]: Inject[F, EitherK[F, G, ?]] =
new Inject[F, EitherK[F, G, ?]] {
implicit def catsLeftInjectKInstance[F[_], G[_]]: InjectK[F, EitherK[F, G, ?]] =
new InjectK[F, EitherK[F, G, ?]] {
val inj = λ[FunctionK[F, EitherK[F, G, ?]]](EitherK.leftc(_))

val prj = λ[FunctionK[EitherK[F, G, ?], λ[α => Option[F[α]]]]](_.run.left.toOption)
}

implicit def catsRightInjectInstance[F[_], G[_], H[_]](implicit I: Inject[F, G]): Inject[F, EitherK[H, G, ?]] =
new Inject[F, EitherK[H, G, ?]] {
implicit def catsRightInjectKInstance[F[_], G[_], H[_]](implicit I: InjectK[F, G]): InjectK[F, EitherK[H, G, ?]] =
new InjectK[F, EitherK[H, G, ?]] {
val inj = λ[FunctionK[G, EitherK[H, G, ?]]](EitherK.rightc(_)) compose I.inj

val prj = λ[FunctionK[EitherK[H, G, ?], λ[α => Option[F[α]]]]](_.run.right.toOption.flatMap(I.prj(_)))
}
}

object Inject extends InjectInstances {
def apply[F[_], G[_]](implicit I: Inject[F, G]): Inject[F, G] = I
object InjectK extends InjectKInstances {
def apply[F[_], G[_]](implicit I: InjectK[F, G]): InjectK[F, G] = I
}
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/Show.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import cats.functor.Contravariant
* explicitly provided one.
*/
@typeclass trait Show[-T] {
def show(f: T): String
def show(t: T): String
}

object Show {
Expand Down
36 changes: 0 additions & 36 deletions core/src/main/scala/cats/Traverse.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,6 @@ import simulacrum.typeclass
*/
def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B]]

/**
* Behaves just like traverse, but uses [[Unapply]] to find the
* Applicative instance for G.
*
* Example:
* {{{
* scala> import cats.implicits._
* scala> def parseInt(s: String): Either[String, Int] = Either.catchOnly[NumberFormatException](s.toInt).leftMap(_ => "no number")
* scala> val ns = List("1", "2", "3")
* scala> ns.traverseU(parseInt)
* res0: Either[String, List[Int]] = Right(List(1, 2, 3))
* scala> ns.traverse[Either[String, ?], Int](parseInt)
* res1: Either[String, List[Int]] = Right(List(1, 2, 3))
* }}}
*/
def traverseU[A, GB](fa: F[A])(f: A => GB)(implicit U: Unapply[Applicative, GB]): U.M[F[U.A]] =
U.TC.traverse(fa)(a => U.subst(f(a)))(this)

/**
* A traverse followed by flattening the inner result.
*
Expand Down Expand Up @@ -101,24 +83,6 @@ import simulacrum.typeclass
def flatSequence[G[_], A](fgfa: F[G[F[A]]])(implicit G: Applicative[G], F: FlatMap[F]): G[F[A]] =
G.map(sequence(fgfa))(F.flatten)

/**
* Behaves just like sequence, but uses [[Unapply]] to find the
* Applicative instance for G.
*
* Example:
* {{{
* scala> import cats.data.{Validated, ValidatedNel}
* scala> import cats.implicits._
* scala> val x: List[ValidatedNel[String, Int]] = List(Validated.valid(1), Validated.invalid("a"), Validated.invalid("b")).map(_.toValidatedNel)
* scala> x.sequenceU
* res0: cats.data.ValidatedNel[String,List[Int]] = Invalid(NonEmptyList(a, b))
* scala> x.sequence[ValidatedNel[String, ?], Int]
* res1: cats.data.ValidatedNel[String,List[Int]] = Invalid(NonEmptyList(a, b))
* }}}
*/
def sequenceU[GA](fga: F[GA])(implicit U: Unapply[Applicative, GA]): U.M[F[U.A]] =
traverse(fga)(U.subst)(U.TC)

def compose[G[_]: Traverse]: Traverse[λ[α => F[G[α]]]] =
new ComposedTraverse[F, G] {
val F = self
Expand Down
14 changes: 14 additions & 0 deletions core/src/main/scala/cats/data/Const.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,20 @@ final case class Const[A, B](getConst: A) {
object Const extends ConstInstances {
def empty[A, B](implicit A: Monoid[A]): Const[A, B] =
Const(A.empty)

final class OfPartiallyApplied[B] {
def apply[A](a: A): Const[A, B] = Const(a)
}

/**
* Convenient syntax for creating a Const[A, B] from an `A`
* {{{
* scala> import cats.data._
* scala> Const.of[Int]("a")
* res0: Const[String, Int] = Const(a)
* }}}
*/
def of[B]: OfPartiallyApplied[B] = new OfPartiallyApplied
}

private[data] sealed abstract class ConstInstances extends ConstInstances0 {
Expand Down
94 changes: 85 additions & 9 deletions core/src/main/scala/cats/data/EitherT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) {
def map[D](f: B => D)(implicit F: Functor[F]): EitherT[F, A, D] = bimap(identity, f)

def semiflatMap[D](f: B => F[D])(implicit F: Monad[F]): EitherT[F, A, D] =
flatMap(b => EitherT.right[F, A, D](f(b)))
flatMap(b => EitherT.right(f(b)))

def leftMap[C](f: A => C)(implicit F: Functor[F]): EitherT[F, C, B] = bimap(f, identity)

Expand Down Expand Up @@ -195,17 +195,13 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) {
* | EitherT(List(Either.right(_.toString), Either.left("error")))
* scala> val fa: EitherT[List, String, Int] =
* | EitherT(List(Either.right(1), Either.right(2)))
* scala> type ErrorOr[A] = Either[String, A]
* scala> type ListErrorOr[A] = Nested[List, ErrorOr, A]
* scala> type ListErrorOr[A] = Nested[List, Either[String, ?], A]
* scala> ff.ap(fa)
* res0: EitherT[List,String,String] = EitherT(List(Right(1), Right(2), Left(error)))
* scala> EitherT((ff.toNested: ListErrorOr[Int => String]).ap(fa.toNested: ListErrorOr[Int]).value)
* res1: EitherT[List,String,String] = EitherT(List(Right(1), Right(2), Left(error), Left(error)))
* }}}
*
* Note that we need the `ErrorOr` type alias above because otherwise we can't use the
* syntax function `ap` on `Nested[List, Either[A, ?], B]`. This won't be needed after cats has
* decided [[https://github.com/typelevel/cats/issues/1073 how to handle the SI-2712 fix]].
*/
def toNested: Nested[F, Either[A, ?], B] = Nested[F, Either[A, ?], B](value)

Expand Down Expand Up @@ -236,11 +232,78 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) {
object EitherT extends EitherTInstances with EitherTFunctions

private[data] trait EitherTFunctions {
final def left[F[_], A, B](fa: F[A])(implicit F: Functor[F]): EitherT[F, A, B] = EitherT(F.map(fa)(Either.left))

final def right[F[_], A, B](fb: F[B])(implicit F: Functor[F]): EitherT[F, A, B] = EitherT(F.map(fb)(Either.right))
final class LeftPartiallyApplied[B] private[EitherTFunctions] {
def apply[F[_], A](fa: F[A])(implicit F: Functor[F]): EitherT[F, A, B] = EitherT(F.map(fa)(Either.left))
}

/**
* Creates a left version of `EitherT[F, A, B]` from a `F[A]`
* {{{
* scala> import cats.data.EitherT
* scala> import cats.implicits._
* scala> EitherT.left[Int](Option("err"))
* res0: cats.data.EitherT[Option,String,Int] = EitherT(Some(Left(err)))
* }}}
*/
final def left[B]: LeftPartiallyApplied[B] = new LeftPartiallyApplied[B]

final class LeftTPartiallyApplied[F[_], B] private[EitherTFunctions] {
def apply[A](a: A)(implicit F: Applicative[F]): EitherT[F, A, B] = EitherT(F.pure(Either.left(a)))
}

/**
* Creates a left version of `EitherT[F, A, B]` from a `A`
* {{{
* scala> import cats.data.EitherT
* scala> import cats.implicits._
* scala> EitherT.leftT[Option, Int]("err")
* res0: cats.data.EitherT[Option,String,Int] = EitherT(Some(Left(err)))
* }}}
*/
final def leftT[F[_], B]: LeftTPartiallyApplied[F, B] = new LeftTPartiallyApplied[F, B]

final class RightPartiallyApplied[A] private[EitherTFunctions] {
def apply[F[_], B](fb: F[B])(implicit F: Functor[F]): EitherT[F, A, B] = EitherT(F.map(fb)(Either.right))
}

/**
* Creates a right version of `EitherT[F, A, B]` from a `F[B]`
* {{{
* scala> import cats.data.EitherT
* scala> import cats.implicits._
* scala> EitherT.right[String](Option(3))
* res0: cats.data.EitherT[Option,String,Int] = EitherT(Some(Right(3)))
* }}}
*/
final def right[A]: RightPartiallyApplied[A] = new RightPartiallyApplied[A]

final class PurePartiallyApplied[F[_], A] private[EitherTFunctions] {
def apply[B](b: B)(implicit F: Applicative[F]): EitherT[F, A, B] = right(F.pure(b))
}

/**
* Creates a new `EitherT[F, A, B]` from a `B`
* {{{
* scala> import cats.data.EitherT
* scala> import cats.implicits._
* scala> EitherT.pure[Option, String](3)
* res0: cats.data.EitherT[Option,String,Int] = EitherT(Some(Right(3)))
* }}}
*/
final def pure[F[_], A]: PurePartiallyApplied[F, A] = new PurePartiallyApplied[F, A]

/**
* Alias for [[pure]]
* {{{
* scala> import cats.data.EitherT
* scala> import cats.implicits._
* scala> EitherT.rightT[Option, String](3)
* res0: cats.data.EitherT[Option,String,Int] = EitherT(Some(Right(3)))
* }}}
*/
final def rightT[F[_], A]: PurePartiallyApplied[F, A] = pure

final def pure[F[_], A, B](b: B)(implicit F: Applicative[F]): EitherT[F, A, B] = right(F.pure(b))

/**
* Alias for [[right]]
Expand Down Expand Up @@ -295,6 +358,19 @@ private[data] trait EitherTFunctions {
EitherT(F.pure(Either.fromOption(opt, ifNone)))
}

/** Transforms an `F[Option]` into an `EitherT`, using the second argument if the `Option` is a `None`.
* {{{
* scala> import cats.implicits._
* scala> val o: Option[Int] = None
* scala> EitherT.fromOptionF(List(o), "Answer not known.")
* res0: EitherT[List, String, Int] = EitherT(List(Left(Answer not known.)))
* scala> EitherT.fromOptionF(List(Option(42)), "Answer not known.")
* res1: EitherT[List, String, Int] = EitherT(List(Right(42)))
* }}}
*/
final def fromOptionF[F[_], E, A](fopt: F[Option[A]], ifNone: => E)(implicit F: Functor[F]): EitherT[F, E, A] =
EitherT(F.map(fopt)(opt => Either.fromOption(opt, ifNone)))

/** If the condition is satisfied, return the given `A` in `Right`
* lifted into the specified `Applicative`, otherwise, return the
* given `E` in `Left` lifted into the specified `Applicative`.
Expand Down
3 changes: 0 additions & 3 deletions core/src/main/scala/cats/data/Func.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ object Func extends FuncInstances {
def run: A => F[B] = run0
}

/** applicative function using [[Unapply]]. */
def appFuncU[A, R](f: A => R)(implicit RR: Unapply[Applicative, R]): AppFunc[RR.M, A, RR.A] =
appFunc({ a: A => RR.subst(f(a)) })(RR.TC)
}

private[data] abstract class FuncInstances extends FuncInstances0 {
Expand Down
Loading

0 comments on commit 17bf536

Please sign in to comment.