9
votes

From Josh Suereth's "Scala in Depth":

"Applicative functors provide a way to take two computations and join them together using a function. The Traversable example highlights how two collections can be parallelized into pairs. Applicative functors and parallel processing go together like bread and butter."

I have a vague idea of the whole functors/monads/applicative stuff, but not exactly a strong grasp of it (new to the whole monad, functor stuff). I understand a bit of the concept of monads (flatten, flatMap) and monadic workflow, and functors (maps).

Can anyone please elaborate for me in terms of how it's done, examples, and/or benefits of it versus "traditional" parallelization?

1
I have an example in my slidesVlad Patryshev

1 Answers

13
votes

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)