I forwarded the question to Josh Suereth. This is his reply:
Mike -
I don't have a lot of time to respond, but I'll offer to examples of
what I mean:
Example #1 - Form Validation.
I want to run some validation against input and aggregate all the
errors, i.e. detect them in parallel. With applicative functions I
can do so.
So, given a set of "processing" functions, like so:
def processUser(data: Data): Validation[User] = {
if (data get "username" isEmpty) Failure("username must not be empty")
else {
val Some(user) = data get "username"
if (user contains badCharacterRegex) Failure(s"username must not contain one of ${badchars}")
else Success(user)
}
}
def processCreditCard(data: Data): Validation[CreditCard] = ...
def processAddress(data: Data): Validation[Address] = ...
def handleForm(data: Data): ??? = {
(processUser(data), processCreditCard(data), processAddress(data)) map { (user, card, address) =>
postPayment(user, address, card)
} recover { (errors) =>
errors foreach println
}
Now handle form will print out errors with CreditCard/username +
address all at the same time, since you've combined them using an
applicative functor. That's parallel error reporting (although
testing isn't actually done in parallel).
(2) Futures
I want to do a few things in parallel and combine results. Future's
"zip" method is actually an applicative functor in disguise. I can do
this:
Future(computation1) zip Future(computation2) map { case (one,two) => .... }
I've just used Applicative Functors to "join" parallel computations.
It's exactly the same as the Form validation example.
Hope that helps!
- Josh
(note these code snippets are non-compilable examples; I was using SBT's applicative syntax with the concepts in Scalaz, so you need to choose a library to use applicatives and what they are applying onto)