Skip to content

Instantly share code, notes, and snippets.

@krasserm
Created December 19, 2010 19:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save krasserm/747597 to your computer and use it in GitHub Desktop.
Save krasserm/747597 to your computer and use it in GitHub Desktop.
import scalaz._
object ValidationApplicative extends Application {
import Scalaz._
// -----------------------------------------------------------------------------------
// Applicative use of scalaz.Validation to combine results of independent computations
// e.g. results from multiple recipients, see also multicast EIP in scalaz-camel: http://goo.gl/FXWRi
// -----------------------------------------------------------------------------------
case class Message(b: String) {
def append(s: String) = Message(b + s)
}
type MessageProcessor = Message => Validation[Exception, Message]
def append(s: String): MessageProcessor = (m: Message) => m.append(s).success
def fail(msg: String): MessageProcessor = (m: Message) => (new Exception(msg)).fail
val lastMsg = (m1: Message) => (m2: Message) => m2
// List of (independent) computations where some of them fail
val computations1 = List(append("-1"), fail("f1"), fail("f2"), append("-2"), append("-3"))
// List of (independent) computations where all succeed
val computations2 = List(append("-1"), append("-2"), append("-3"))
// Run independent computations sequentially (3x success, 2x failure)
val results1 = Message("a").pure[List] <*> computations1
// Run independent computations sequentially (3x success)
val results2 = Message("a").pure[List] <*> computations2
{
// Makes Exception an instance of Semigroup type class (select first exception)
implicit def ExceptionSemigroup: Semigroup[Exception] = semigroup((e1, e2) => e1)
// combine Validation results in list via foldLeft
println(results1.tail.foldLeft(results1.head) { (z, m) => m <*> z ∘ lastMsg }) // Failure(java.lang.Exception: f1)
println(results2.tail.foldLeft(results2.head) { (z, m) => m <*> z ∘ lastMsg }) // Success(Message(a-3))
// Alternative
results1.sequence[PartialApply1Of2[Validation, Exception]#Apply, Message] match {
case Success(l) => println(l.last.success)
case Failure(e) => println(e.fail) // Failure(java.lang.Exception: f1)
}
results2.sequence[PartialApply1Of2[Validation, Exception]#Apply, Message] match {
case Success(l) => println(l.last.success) // Success(Message(a-3))
case Failure(e) => println(e.fail)
}
}
{
// Makes Exception an instance of Semigroup type class (select second exception)
implicit def ExceptionSemigroup: Semigroup[Exception] = semigroup((e1, e2) => e2)
// combine Validation results in list via foldLeft
println(results1.tail.foldLeft(results1.head) { (z, m) => m <*> z ∘ lastMsg }) // Failure(java.lang.Exception: f2)
println(results2.tail.foldLeft(results2.head) { (z, m) => m <*> z ∘ lastMsg }) // Success(Message(a-3))
}
}
@retronym
Copy link

Take a look at MA#sequence, allowing List[Validation[A, B]] => Validation[A, List[B]], given A: Semigroup.

@krasserm
Copy link
Author

Thanks for the pointer, Jason. Updated the example again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment