Skip to content

Instantly share code, notes, and snippets.

@jayhutfles
Last active November 20, 2015 15:45
Show Gist options
  • Save jayhutfles/deca344c8be2f853b2b4 to your computer and use it in GitHub Desktop.
Save jayhutfles/deca344c8be2f853b2b4 to your computer and use it in GitHub Desktop.
Differences between Xor and Validated in Cats
import cats._
import cats.data._
import cats.std.all._
import cats.syntax.apply._
object ValidationExamples {
type WhyNot = List[String]
type Good[A] = Xor[WhyNot, A]
type Proven[A] = Validated[WhyNot, A]
trait TryingGood {
def a(s: String): Good[Int]
def b(s: String): Good[Int]
def c(s: String): Good[(Int, Int)] = (a(s) |@| b(s)) map { (_, _) }
def l(s: String): Good[Int] = a(s) <* b(s)
def r(s: String): Good[Int] = a(s) *> b(s)
}
trait TryingProven {
def a(s: String): Proven[Int]
def b(s: String): Proven[Int]
def c(s: String): Proven[(Int, Int)] = (a(s) |@| b(s)) map { (_, _) }
def l(s: String): Proven[Int] = a(s) <* b(s)
def r(s: String): Proven[Int] = a(s) *> b(s)
}
object GoodTry extends TryingGood {
def a(s: String) = if (s.length % 2 == 0) Xor.right(s.length) else Xor.left(List("string '" + s + "' has odd length"))
def b(s: String) = try { Xor.right(s.toInt) } catch { case e: NumberFormatException => Xor.left(List("can't parse to Int")) }
}
object ProvenTry extends TryingProven {
def a(s: String) = if (s.length % 2 == 0) Validated.valid(s.length) else Validated.invalid(List("string '" + s + "' has odd length"))
def b(s: String) = try { Validated.valid(s.toInt) } catch { case e: NumberFormatException => Validated.invalid(List("can't parse to Int")) }
}
val inputs = List("12", "1", "ab", "a")
val goodTuple = inputs.map(GoodTry.c(_))
// "12" => Right((2,12))
// "1" => Left(List(string '1' has odd length)) // FIRST FAILURE
// "ab" => Left(List(can't parse to Int)) // SECOND FAILURE
// "a" => Left(List(string 'a' has odd length)) // JUST THE FIRST OF THE TWO FAILURES
val goodLeft = inputs.map(GoodTry.l(_))
// "12" => Right(2) // JUST THE LEFT OF THE TWO COMPOSED APPLICATIVES
// "1" => Left(List(string '1' has odd length)) // FIRST FAILURE
// "ab" => Left(List(can't parse to Int)) // SECOND FAILURE
// "a" => Left(List(string 'a' has odd length)) // JUST THE FIRST OF THE TWO FAILURES
val goodRight = inputs.map(GoodTry.r(_))
// "12" => Right(12) // JUST THE RIGHT OF THE TWO COMPOSED APPLICATIVES
// "1" => Left(List(string '1' has odd length)) // FIRST FAILURE
// "ab" => Left(List(can't parse to Int)) // SECOND FAILURE
// "a" => Left(List(string 'a' has odd length)) // JUST THE FIRST OF THE TWO FAILURES
val provenTuple = inputs.map(ProvenTry.c(_))
// "12" => Valid((2,12))
// "1" => Invalid(List(string '1' has odd length)) // FIRST FAILURE
// "ab" => Invalid(List(can't parse to Int)) // SECOND FAILURE
// "a" => Invalid(List(string 'a' has odd length, can't parse to Int)) // BOTH FAILURES
val provenLeft = inputs.map(ProvenTry.l(_))
// "12" => Valid(2) // JUST THE LEFT OF THE TWO COMPOSED APPLICATIVES
// "1" => Invalid(List(string '1' has odd length)) // FIRST FAILURE
// "ab" => Invalid(List(can't parse to Int)) // SECOND FAILURE
// "a" => Invalid(List(string 'a' has odd length, can't parse to Int)) // BOTH FAILURES
val provenRight = inputs.map(ProvenTry.r(_))
// "12" => Valid(12) // JUST THE RIGHT OF THE TWO COMPOSED APPLICATIVES
// "1" => Invalid(List(string '1' has odd length)) // FIRST FAILURE
// "ab" => Invalid(List(can't parse to Int)) // SECOND FAILURE
// "a" => Invalid(List(string 'a' has odd length, can't parse to Int)) // BOTH FAILURES
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment