From the example you provided, it can quite easily be shown that the
tuuraHtml function is free from side effects (it takes a pure value of
the database state and produces a pure Html). This is one advantage of
this Haskell code over equivalent Java/C#.
Another advantage is that the Html is produced lazily, i.e. the
functions are only evaluated when needed. This makes it very different
from an imperative implementation. It may allow to reduce the
roundtrip latency by starting the transmission earlier or even to
produce an otherwise impossible response of unbounded size.
Third advantage is the Haskell's terse notation. A semantically close
(mostly functional except for "for" loop) function in Java could look
like:
Html tuuraHtml(TuuraDb db) {
ArrayList<Html> problemTableLines = new ArrayList<Html>();
for(ProblemInfo problem : db.problems().values())
problemTableLines.add(problemHtml(problem));
return html(sequence(
head(title("Tuura page!")),
body(sequence(
withAttribute(a(),
A.href("/tuura/addProblem")).enclose("Add a new problem"),
p("Available problems:"),
sequenceList(problemTableLines)
)
));
}
Which is much uglier.
I doubt it will look much nicer if you fully convert it to imperative
style. And even if it will, such a conversion will probably reduce
(de-)composability of your code.
And, if you mention the "do" notation, it does not do anything
"monady" in this case because it is only used for sequencing the HTML
elements, not some clever computations. Monoid instance for Html would
be enough, but the code laid out with "do" notation just looks nicer.
Oh, no, I am helping to start a holywar... :(
> Your final implementation of renderTable is close to what I'd like to
> see in the end but will you be able to write everything in this style?
Well, there is always a trade-off between the effort and the quality
of product (code clarity in this case). Who knows where the optimum
is. The renderTable-style commenting is almost certainly too much
though. It's kind of similar to the comments like
for(int i=0;i<n;i++) // iterate over the [0..n) interval using i as
the loop counter
> Isn't it similar to "translation of a bad imperative program line-by-
> line without changing anything"?
I find no similarity at all. No assignments here, no implicit
state-carrying with the help of monads. (Okay, formally there is a
Html monad, but it is not really used as a monad here)
> I just don't want
> to scare away any potential contributors by perfectionism which is
> difficult to comprehend.
Haskell will scare some away, no matter if the code is comprehensible
or not, for Haskell has a smaller user base and no advanced IDE I
know of. However, I find programming in Haskell much more fun and
rewarding (e.g. "it compiles -> it probably works" relation is a very
pleasant one), so the remaining unscared-by-Haskell contributors
should be able to do more than they'd do in other language. :)
Maybe a difficult trade-off decision for project, but an easy decision for me.
I know of three HTML templating options for Haskell: Heist, Hamlet and HSP.
Heist seems to be a port of Scala Lift's template engine, inheriting
both its strengths and weaknesses.
Hamlet does a compile-time code generation with Template Haskell from
the HTML-like templates with full type-checking. It can even
type-check CSS classes and URLs, which is impressive! However, the
language it uses is not exactly HTML (see examples in
http://docs.yesodweb.com/book/templates), which Ivan found terrible,
but I find rather OK.
HSP does a template pre-processing with a separate tool before feeding
it to the Haskell compiler, in a way similar to ASP.NET. You can see
examples in a paper at
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.21.9537&rep=rep1&type=pdf
The HTML used is more well-formed than the Hamlet's one, but still is
not a valid XML in constrast to Heist approach.