HStringTemplate is a port of Terrence Parr’s lovely StringTemplate engine to Haskell.
It is available, cabalized, at:
darcs get http://code.haskell.org/HStringTemplate/
As interest has grown in using Haskell for web applications, there has been an increasing buzz about the need for a good templating engine in Haskell. Why might we need this? After all, Haskell has lovely combinator libraries for generating HTML programmatically, enforcing good form through its type system. But sometimes, we don’t want well-formed HTML. We want the ugly stuff that floats around to deal with eight varieties of browser incompatibilities and the latest silly ajax trick. Or sometimes we’re working with a team of graphic designers, and they want to work in almost-HTML. Or sometimes we just want to be able to change the design of a web application on the fly, completely independent of our program logic, and of, heavens forbid, recompiling and possibly messing with a live application.
So template engines are popular, and indeed, considered a key part of most web frameworks out there. One problem — they’re mainly awful, imperatively-conceived behemoths that capriciously mix program logic with display and, consequently, entail a great deal of overhead. Enter StringTemplate, a nifty and fairly-well developed template format that’s both pure and functional, and therefore pretty much the only one of its kind. Indeed, it also seems to be getting heavy use in code generation because its paradigm maps neatly to traversing parse-trees.
HStringTemplate is not feature-complete, and indeed is only at version 0.1. But it should implement pretty much everything you’ll find here, only nicer, because it’s in Haskell. There are scads of different recursive constructs and ways to handle inclusion and inheritance. Furthermore, HStringTemplate handles conditionals, and also a very Haskellish implementation of custom rendering.
Templates can be constructed that return strings, ShowSs, bytestrings, or even pretty printer Docs that handle wrapping, indentation, and fill elegantly. Even better, these templates are parsed and compiled only once, after which point there isn’t a syntax tree anymore, just a function that operates on the environment of attributes that have been passed to it.
Ok. Enough talk. Let’s look at a sample GHCi session. Note that when defining “hello” we have to give the signature explicitly, as it’s not clear until later what type of StringTemplate we’re expecting.
> let hello = newSTMP "something $foo;separator='; '$ something" :: StringTemplate String
> toString $ setAttribute "foo" "SomethingElse" hello
"something SomethingElse something"
> toString $ setAttribute "foo" ["a","b","c"] hello
"something a; b; c something"
> toString $ setAttribute "foo" ([1..10]::[Double]) hello
"something 1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; 9.0; 10.0 something"
And that should be enough to get you started! Be sure to check the haddocks as well, which cover the API in some more detail.
Where I take it from here depends in part on what sort of response I get, so patches, gripes, API comments and feature requests are all more than welcome.
Meanwhile, I’ve learned quite a bit doing this, and suspect that once the benchmarks are in, this will in fact turn out to be a fairly lean and mean implementation compared to the Java one. As a matter of fact, it currently stands at, excluding tests, 414 lines of code. The Java version, admittedly somewhat more featureful, runs in the vicinity of 12,000! Over the next few weeks, I plan to blog about some of my “aha” moments, mainly involving monoids and their many delicious instances.