TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Applicative Programming, Disjoint Unions, Semigroups and Non-breaking Errors

27 pointsby pufuwozuover 14 years ago

4 comments

T_S_over 14 years ago
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?!"
pufuwozuover 14 years ago
PDF version:<p><a href="http://applicative-errors-scala.googlecode.com/svn/artifacts/0.6/pdf/index.pdf" rel="nofollow">http://applicative-errors-scala.googlecode.com/svn/artifacts...</a>
samstokesover 14 years ago
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.<p>The punchline:<p><pre><code> val f = (Person(_, _, _)).curried val age = validAge(args(0)) val name = validName(args(1)) val postcode = validPostcode(args(2)) postcode &#60;&#60;*&#62;&#62; (name &#60;&#60;*&#62;&#62; (age map f)) match { case Success(p) =&#62; println("We have a person: " + p) case Failure(e) =&#62; e foreach println } </code></pre> 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 &#60;&#60;star&#62;&#62; and vmap:<p><pre><code> instance Functor (Validation e) where fmap = flip vmap instance Semigroup e =&#62; Applicative (Validation e) where pure = Success (&#60;*&#62;) = flip (&#60;&#60;*&#62;&#62;) </code></pre> you can write the constructor call in the natural order:<p><pre><code> Person &#60;$&#62; age &#60;*&#62; name &#60;*&#62; postcode </code></pre> which is obviously analogous to what the call would look like without error handling:<p><pre><code> Person age name postcode </code></pre> 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 <i>without</i> much disruption to existing code.<p>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:<p><pre><code> data Section = HostSection {hostNames :: [String], hostOptions :: [HostOption]} hostSectionP :: CharParser st Section -- hostSectionP parses Chars and produces a Section hostSectionP = HostSection &#60;$&#62; hostHeaderP &#60;*&#62; many1 hostOptionP -- many1 is like '+' in regex</code></pre>
loewenskindover 14 years ago
From the Haskell code it looks to me like the &#60;&#60;*&#62;&#62; operator is doing a monoid append, no?