Skip to content

Commit

Permalink
merge from upstream/master; for typelevel#803 reversing order of para…
Browse files Browse the repository at this point in the history
…m lists for Apply.ap
  • Loading branch information
lukewyman committed Jan 20, 2016
2 parents f286f2d + 722ce05 commit 516bf91
Show file tree
Hide file tree
Showing 24 changed files with 484 additions and 138 deletions.
21 changes: 20 additions & 1 deletion AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,47 +14,66 @@ possible:

* Adelbert Chang
* Alessandro Lacava
* Alexey Levan
* Alissa Pajer
* Alistair Johnson
* Amir Mohammad Saied
* Andrew Jones
* Antoine Comte
* Arya Irani
* Ash Pook
* Benjamin Thuillier
* Bobby
* Bobby Rauchenberg
* Brendan McAdams
* Cody Allen
* Colt Frederickson
* Dale Wijnand
* Dave Rostron
* David Allsopp
* David Gregory
* Denis Mikhaylov
* Derek Wickern
* Edmund Noble
* Erik LaBianca
* Erik Osheim
* Eugene Burmako
* Eugene Yokota
* Feynman Liang
* Frank S. Thomas
* Jean-Rémi Desjardins
* Jisoo Park
* Josh Marcus
* Julien Richard-Foy
* Julien Truffaut
* Kenji Yoshida
* Long Cao
* Luis Angel Vicente Sanchez
* Luke Wyman
* Marc Siegel
* Markus Hauck
* Matthias Lüneberg
* Michael Pilquist
* Mike Curry
* Miles Sabin
* Olli Helenius
* Owen Parry
* Pascal Voitot
* Paul Phillips
* Philip Wills
* Raúl Raja Martínez
* Rintcius Blok
* Rob Norris
* Romain Ruetschi
* Ross A. Baker
* Sarunas Valaskevicius
* Shunsuke Otani
* Sinisa Louc
* Stephen Judkins
* Stew O'Connor
* Sumedh Mungee
* Travis Brown
* Wedens
* Yosef Fertel
* Zach Abbott

We've tried to include everyone, but if you've made a contribution to
Expand Down
81 changes: 81 additions & 0 deletions core/src/main/scala/cats/ApplicativeError.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package cats

import cats.data.{Xor, XorT}

/**
* An applicative that also allows you to raise and or handle an error value.
*
* This type class allows one to abstract over error-handling applicatives.
*/
trait ApplicativeError[F[_], E] extends Applicative[F] {
/**
* Lift an error into the `F` context.
*/
def raiseError[A](e: E): F[A]

/**
* Handle any error, potentially recovering from it, by mapping it to an
* `F[A]` value.
*
* @see [[handleError]] to handle any error by simply mapping it to an `A`
* value instead of an `F[A]`.
*
* @see [[recoverWith]] to recover from only certain errors.
*/
def handleErrorWith[A](fa: F[A])(f: E => F[A]): F[A]

/**
* Handle any error, by mapping it to an `A` value.
*
* @see [[handleErrorWith]] to map to an `F[A]` value instead of simply an
* `A` value.
*
* @see [[recover]] to only recover from certain errors.
*/
def handleError[A](fa: F[A])(f: E => A): F[A] = handleErrorWith(fa)(f andThen pure)

/**
* Handle errors by turning them into [[cats.data.Xor.Left]] values.
*
* If there is no error, then an [[cats.data.Xor.Right]] value will be returned instead.
*
* All non-fatal errors should be handled by this method.
*/
def attempt[A](fa: F[A]): F[E Xor A] = handleErrorWith(
map(fa)(Xor.right[E, A])
)(e => pure(Xor.left(e)))

/**
* Similar to [[attempt]], but wraps the result in a [[cats.data.XorT]] for
* convenience.
*/
def attemptT[A](fa: F[A]): XorT[F, E, A] = XorT(attempt(fa))

/**
* Recover from certain errors by mapping them to an `A` value.
*
* @see [[handleError]] to handle any/all errors.
*
* @see [[recoverWith]] to recover from certain errors by mapping them to
* `F[A]` values.
*/
def recover[A](fa: F[A])(pf: PartialFunction[E, A]): F[A] =
handleErrorWith(fa)(e =>
(pf andThen pure) applyOrElse(e, raiseError))

/**
* Recover from certain errors by mapping them to an `F[A]` value.
*
* @see [[handleErrorWith]] to handle any/all errors.
*
* @see [[recover]] to recover from certain errors by mapping them to `A`
* values.
*/
def recoverWith[A](fa: F[A])(pf: PartialFunction[E, F[A]]): F[A] =
handleErrorWith(fa)(e =>
pf applyOrElse(e, raiseError))
}

object ApplicativeError {
def apply[F[_], E](implicit F: ApplicativeError[F, E]): ApplicativeError[F, E] = F
}
49 changes: 48 additions & 1 deletion core/src/main/scala/cats/Foldable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,31 @@ import simulacrum.typeclass
G.map2(acc, f(a)) { (_, _) => () }
}

/**
* 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 [[cats.data.Xor]]
*
* {{{
* scala> import cats.data.Xor
* scala> import cats.std.list._
* scala> def parseInt(s: String): Xor[String, Int] =
* | try { Xor.Right(s.toInt) }
* | catch { case _: NumberFormatException => Xor.Left("boo") }
* scala> val F = Foldable[List]
* scala> F.traverseU_(List("333", "444"))(parseInt)
* res0: Xor[String, Unit] = Right(())
* scala> F.traverseU_(List("333", "zzz"))(parseInt)
* res1: Xor[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 @@ -125,9 +150,31 @@ import simulacrum.typeclass
* res1: Option[Unit] = None
* }}}
*/
def sequence_[G[_]: Applicative, A, B](fga: F[G[A]]): G[Unit] =
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 [[cats.data.Xor]]
*
* {{{
* scala> import cats.data.Xor
* scala> import cats.std.list._
* scala> val F = Foldable[List]
* scala> F.sequenceU_(List(Xor.right[String, Int](333), Xor.Right(444)))
* res0: Xor[String, Unit] = Right(())
* scala> F.sequenceU_(List(Xor.right[String, Int](333), Xor.Left("boo")))
* res1: Xor[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
69 changes: 1 addition & 68 deletions core/src/main/scala/cats/MonadError.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,74 +7,7 @@ import cats.data.{Xor, XorT}
*
* This type class allows one to abstract over error-handling monads.
*/
trait MonadError[F[_], E] extends Monad[F] {
/**
* Lift an error into the `F` context.
*/
def raiseError[A](e: E): F[A]

/**
* Handle any error, potentially recovering from it, by mapping it to an
* `F[A]` value.
*
* @see [[handleError]] to handle any error by simply mapping it to an `A`
* value instead of an `F[A]`.
*
* @see [[recoverWith]] to recover from only certain errors.
*/
def handleErrorWith[A](fa: F[A])(f: E => F[A]): F[A]

/**
* Handle any error, by mapping it to an `A` value.
*
* @see [[handleErrorWith]] to map to an `F[A]` value instead of simply an
* `A` value.
*
* @see [[recover]] to only recover from certain errors.
*/
def handleError[A](fa: F[A])(f: E => A): F[A] = handleErrorWith(fa)(f andThen pure)

/**
* Handle errors by turning them into [[cats.data.Xor.Left]] values.
*
* If there is no error, then an [[cats.data.Xor.Right]] value will be returned instead.
*
* All non-fatal errors should be handled by this method.
*/
def attempt[A](fa: F[A]): F[E Xor A] = handleErrorWith(
map(fa)(Xor.right[E, A])
)(e => pure(Xor.left(e)))

/**
* Similar to [[attempt]], but wraps the result in a [[cats.data.XorT]] for
* convenience.
*/
def attemptT[A](fa: F[A]): XorT[F, E, A] = XorT(attempt(fa))

/**
* Recover from certain errors by mapping them to an `A` value.
*
* @see [[handleError]] to handle any/all errors.
*
* @see [[recoverWith]] to recover from certain errors by mapping them to
* `F[A]` values.
*/
def recover[A](fa: F[A])(pf: PartialFunction[E, A]): F[A] =
handleErrorWith(fa)(e =>
(pf andThen pure) applyOrElse(e, raiseError))

/**
* Recover from certain errors by mapping them to an `F[A]` value.
*
* @see [[handleErrorWith]] to handle any/all errors.
*
* @see [[recover]] to recover from certain errors by mapping them to `A`
* values.
*/
def recoverWith[A](fa: F[A])(pf: PartialFunction[E, F[A]]): F[A] =
handleErrorWith(fa)(e =>
pf applyOrElse(e, raiseError))
}
trait MonadError[F[_], E] extends ApplicativeError[F, E] with Monad[F]

object MonadError {
def apply[F[_], E](implicit F: MonadError[F, E]): MonadError[F, E] = F
Expand Down
48 changes: 48 additions & 0 deletions core/src/main/scala/cats/arrow/Arrow.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,58 @@ import cats.functor.Strong

trait Arrow[F[_, _]] extends Split[F] with Strong[F] with Category[F] { self =>

/**
* Lift a function into the context of an Arrow
*/
def lift[A, B](f: A => B): F[A, B]

/**
* Create a new arrow from an existing arrow that applies `f` to the input
* of the original arrow and then applies `g` to the output.
*
* Example:
* {{{
* scala> import cats.std.function._
* scala> import cats.arrow.Arrow
* scala> val fab: Double => Double = x => x + 0.3
* scala> val f: Int => Double = x => x.toDouble / 2
* scala> val g: Double => Double = x => x * 3
* scala> val dimapArrow = Arrow[Function1].dimap(fab)(f)(g)
* scala> dimapArrow(3)
* res0: Double = 5.4
* }}}
*/
def dimap[A, B, C, D](fab: F[A, B])(f: C => A)(g: B => D): F[C, D] =
compose(lift(g), andThen(lift(f), fab))

/**
* Create a new arrow that takes two inputs, but only modifies the first input
*
* Example:
* {{{
* scala> import cats.std.function._
* scala> import cats.arrow.Arrow
* scala> val f: Int => Int = _ * 2
* scala> val fab = Arrow[Function1].first[Int,Int,Int](f)
* scala> fab((2,3))
* res0: (Int, Int) = (4,3)
* }}}
*/
def first[A, B, C](fa: F[A, B]): F[(A, C), (B, C)]

/**
* Create a new arrow that takes two inputs, but only modifies the second input
*
* Example:
* {{{
* scala> import cats.std.function._
* scala> import cats.arrow.Arrow
* scala> val f: Int => Int = _ * 2
* scala> val fab = Arrow[Function1].second[Int,Int,Int](f)
* scala> fab((2,3))
* res0: (Int, Int) = (2,6)
* }}}
*/
def second[A, B, C](fa: F[A, B]): F[(C, A), (C, B)] = {
def swap[X, Y]: F[(X, Y), (Y, X)] = lift[(X, Y), (Y, X)] { case (x, y) => (y, x) }
compose(swap, compose(first[A, B, C](fa), swap))
Expand All @@ -22,6 +69,7 @@ trait Arrow[F[_, _]] extends Split[F] with Strong[F] with Category[F] { self =>
* Example:
* {{{
* scala> import cats.std.function._
* scala> import cats.arrow.Arrow
* scala> val toLong: Int => Long = _.toLong
* scala> val toDouble: Float => Double = _.toDouble
* scala> val f: ((Int, Float)) => (Long, Double) = Arrow[Function1].split(toLong, toDouble)
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/scala/cats/data/StreamingT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ sealed abstract class StreamingT[F[_], A] extends Product with Serializable { lh
*/
def filter(f: A => Boolean)(implicit ev: Functor[F]): StreamingT[F, A] =
this match {
case Cons(a, ft) => if (f(a)) this else Wait(ft.map(_.filter(f)))
case Cons(a, ft) =>
val tail = ft.map(_.filter(f))
if (f(a)) Cons(a, tail) else Wait(tail)
case Wait(ft) => Wait(ft.map(_.filter(f)))
case Empty() => this
}
Expand Down
11 changes: 9 additions & 2 deletions core/src/main/scala/cats/data/Validated.scala
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,8 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance
override def leftMap[A, B, C](fab: Validated[A, B])(f: A => C): Validated[C, B] = fab.leftMap(f)
}

implicit def validatedInstances[E](implicit E: Semigroup[E]): Traverse[Validated[E, ?]] with Applicative[Validated[E, ?]] =
new Traverse[Validated[E, ?]] with Applicative[Validated[E,?]] {
implicit def validatedInstances[E](implicit E: Semigroup[E]): Traverse[Validated[E, ?]] with ApplicativeError[Validated[E, ?], E] =
new Traverse[Validated[E, ?]] with ApplicativeError[Validated[E, ?], E] {
def traverse[F[_]: Applicative, A, B](fa: Validated[E,A])(f: A => F[B]): F[Validated[E,B]] =
fa.traverse(f)

Expand All @@ -256,6 +256,13 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance

def product[A, B](fa: Validated[E, A], fb: Validated[E, B]): Validated[E, (A, B)] =
fa.product(fb)(E)

def handleErrorWith[A](fa: Validated[E, A])(f: E => Validated[E, A]): Validated[E, A] =
fa match {
case Validated.Invalid(e) => f(e)
case v @ Validated.Valid(_) => v
}
def raiseError[A](e: E): Validated[E, A] = Validated.Invalid(e)
}
}

Expand Down
Loading

0 comments on commit 516bf91

Please sign in to comment.