TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

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

27 点作者 pufuwozu超过 14 年前

4 条评论

T_S_超过 14 年前
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?!"
pufuwozu超过 14 年前
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>
samstokes超过 14 年前
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>
loewenskind超过 14 年前
From the Haskell code it looks to me like the &#60;&#60;*&#62;&#62; operator is doing a monoid append, no?