One of the the reasons I switched to Hakyll was for its purportedly excellent support for literate Haskell. Up until now I hadn’t had a reason to actually test this out - but then I decided to write a longer article on generating certain fractals using Repa. Expect more on that in the near future. Fortunately, I’ve found that the standard Hakyll blog configuration does indeed make blogging in Bird-style literate Haskell utterly trivial: one simply has to install pandoc with support for syntax highlighting, and then switch file extensions from .md to .lhs.
Of course, no software is perfect and so I ended up making a few small improvements to my current codebase… Most urgently, highlighting-kate (the package responsible for syntax highlighting) uses a sub-optimal syntax definition file - in particular, it gives all of the Prelude’s functions a special color. I find this illogical and annoying - uniformity dictates that all identifiers should have the same style - so I recompiled highlighting-kate from the source with the following patch:
--- xml/haskell.xml | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/xml/haskell.xml b/xml/haskell.xml index 7948528..8092ecd 100644 --- a/xml/haskell.xml +++ b/xml/haskell.xml @@ -356,7 +356,7 @@ <itemData name="Keyword" defStyleNum="dsKeyword" spellChecking="false" /> <itemData name="Type Prelude" defStyleNum="dsDataType" spellChecking="false" /> - <itemData name="Function Prelude" defStyleNum="dsFunction" spellChecking="false" /> + <itemData name="Function Prelude" defStyleNum="dsNormal" spellChecking="false" /> <itemData name="Data Prelude" defStyleNum="dsKbeyword" spellChecking="false" /> <itemData name="Class Prelude" defStyleNum="dsKeyword" spellChecking="false" /> --
I also want all literate Haskell posts to have a short blurb at the top stating that they are indeed literate Haskell and are directly executable. Writing a
compiler (in the Hakyll parlance) to insert this blurb is rather simple:
The required modules:
> import Control.Arrow > import Hakyll > import Text.Blaze.Html.Renderer.String (renderHtml) > import qualified Text.Blaze.Html5 as H > import qualified Text.Blaze.Html5.Attributes as A > import Text.Blaze.Html (toValue, (!)) > import Hakyll.Web.Pandoc.FileType > import Prelude hiding (id) > import Control.Category (id)
Then a utility function that sets a field in a page using an arrow to generate the field’s content. This is just a minor wrapper over setFieldA with a much more convenient type - the resultant Compiler (Page String) (Page String) is much easier to compose with other compilers than setFieldA’s Compiler (Page String,a) (Page String).
> setWithArrow::Arrow a=>String->a (Page String) String->a (Page String) (Page String) > setWithArrow field arrow = id &&& arrow >>> setFieldA field id
The compiler to insert the
This is literate Haskell blurb is then trivial to construct from Hakyll.Web.Pandoc.FileType’s getFileType arrow:
> literate::Compiler (Page String) (Page String) > literate = setWithArrow "literate" $ fmap mess getFileType > where mess (LiterateHaskell _) = "This post is literate etc..." > mess _ = ""