Nice quote: "Non-breaking error handling is just an applicative functor on a partially applied disjoint union type constructor with semigroup error elements so what's the big deal?!"
The title is facetiously obfuscated (though accurate): this is about performing a sequence of computations which might throw errors (such as validating input), collecting those errors along the way.
The punchline:
val f = (Person(_, _, _)).curried
val age = validAge(args(0))
val name = validName(args(1))
val postcode = validPostcode(args(2))
postcode <<*>> (name <<*>> (age map f)) match {
case Success(p) => println("We have a person: " + p)
case Failure(e) => e foreach println
}
I'm puzzled by the author's choice of argument order, which means the call to the Person constructor at the end has to be reversed (arguments in reverse order with `f` at the end). In Haskell, using the built-in Applicative typeclass and flipping his definitions of <<star>> and vmap:
instance Functor (Validation e) where
fmap = flip vmap
instance Semigroup e => Applicative (Validation e) where
pure = Success
(<*>) = flip (<<*>>)
you can write the constructor call in the natural order:
Person <$> age <*> name <*> postcode
which is obviously analogous to what the call would look like without error handling:
Person age name postcode
IMHO this shows the power of the technique described more clearly: that with a bit of plumbing up front, you can add arbitrarily sophisticated error handling behaviour without much disruption to existing code.
One of my Haskell 'aha' moments was that you could do this with Parsec (a parsing library) to build data structures in a way that mirrors the grammar being parsed:
data Section = HostSection {hostNames :: [String], hostOptions :: [HostOption]}
hostSectionP :: CharParser st Section -- hostSectionP parses Chars and produces a Section
hostSectionP = HostSection <$> hostHeaderP <*> many1 hostOptionP
-- many1 is like '+' in regex