Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Syntax for ApplicativeError #947

Merged
merged 2 commits into from
Mar 28, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/src/main/scala/cats/syntax/all.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package syntax

trait AllSyntax
extends ApplicativeSyntax
with ApplicativeErrorSyntax
with ApplySyntax
with BifunctorSyntax
with BifoldableSyntax
Expand Down
37 changes: 37 additions & 0 deletions core/src/main/scala/cats/syntax/applicativeError.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package cats
package syntax

import cats.data.{Xor, XorT}

trait ApplicativeErrorSyntax {
implicit def applicativeErrorIdSyntax[E](e: E): ApplicativeErrorIdOps[E] =
new ApplicativeErrorIdOps(e)

implicit def applicativeErrorSyntax[F[_, _], E, A](fa: F[E, A])(implicit F: ApplicativeError[F[E, ?], E]): ApplicativeErrorOps[F[E, ?], E, A] =
new ApplicativeErrorOps[F[E, ?], E, A](fa)
}

final class ApplicativeErrorIdOps[E](e: E) {
def raiseError[F[_], A](implicit F: ApplicativeError[F, E]): F[A] =
F.raiseError(e)
}

final class ApplicativeErrorOps[F[_], E, A](fa: F[A])(implicit F: ApplicativeError[F, E]) {
def handleError(f: E => A): F[A] =
F.handleError(fa)(f)

def handleErrorWith(f: E => F[A]): F[A] =
F.handleErrorWith(fa)(f)

def attempt: F[E Xor A] =
F.attempt(fa)

def attemptT: XorT[F, E, A] =
F.attemptT(fa)

def recover(pf: PartialFunction[E, A]): F[A] =
F.recover(fa)(pf)

def recoverWith(pf: PartialFunction[E, F[A]]): F[A] =
F.recoverWith(fa)(pf)
}
1 change: 1 addition & 0 deletions core/src/main/scala/cats/syntax/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cats
package object syntax {
object all extends AllSyntax
object applicative extends ApplicativeSyntax
object applicativeError extends ApplicativeErrorSyntax
object apply extends ApplySyntax
object bifunctor extends BifunctorSyntax
object bifoldable extends BifoldableSyntax
Expand Down
42 changes: 42 additions & 0 deletions tests/src/test/scala/cats/tests/ApplicativeErrorTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package cats
package tests

import cats.data.{Xor, XorT}

class ApplicativeErrorCheck extends CatsSuite {

type ErrorOr[A] = String Xor A

val failed: String Xor Int =
"Badness".raiseError[ErrorOr, Int]

test("raiseError syntax creates an Xor with the correct type parameters") {
failed should === ("Badness".left[Int])
}

test("handleError syntax transforms an error to a success") {
failed.handleError(error => error.length) should === (7.right)
}

test("handleErrorWith transforms an error to a success") {
failed.handleErrorWith(error => error.length.right) should === (7.right)
}

test("attempt syntax creates a wrapped Xor") {
failed.attempt should === ("Badness".left.right)
}

test("attemptT syntax creates an XorT") {
type ErrorOrT[A] = XorT[ErrorOr, String, A]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't appear to be used. Please tell me that it's mere presence doesn't affect whether the next line compiles? :|

failed.attemptT should === (XorT[ErrorOr, String, Int](failed.right))
}

test("recover syntax transforms an error to a success") {
failed.recover { case error => error.length } should === (7.right)
}

test("recoverWith transforms an error to a success") {
failed.recoverWith { case error => error.length.right } should === (7.right)
}

}
25 changes: 25 additions & 0 deletions tests/src/test/scala/cats/tests/SyntaxTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -214,4 +214,29 @@ class SyntaxTests extends AllInstances with AllSyntax {
val la = mock[Eval[A]]
val lfa = la.pureEval[F]
}

def testApplicativeError[F[_, _], E, A](implicit F: ApplicativeError[F[E, ?], E]): Unit = {
type G[X] = F[E, X]

val e = mock[E]
val ga = e.raiseError[G, A]

val gea = mock[G[A]]

val ea = mock[E => A]
val gea1 = ga.handleError(ea)

val egea = mock[E => G[A]]
val gea2 = ga.handleErrorWith(egea)

val gxea = ga.attempt

val gxtea = ga.attemptT

val pfea = mock[PartialFunction[E, A]]
val gea3 = ga.recover(pfea)

val pfegea = mock[PartialFunction[E, G[A]]]
val gea4 = ga.recoverWith(pfegea)
}
}