Hakyll Snippets
Some utility code for configuring Hakyll for better literate Haskell.
(This post is literate Haskell, and thus may be directly copied into GHC[I])
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" />
--
The syntax definition is still far from perfect, but rewriting it seems very tedious. I also use a custom definition file for Erlang, sourced from this forum post.
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 _ = ""
Additionally, I’ve found that I sometimes want to be able to include links to arbitrary JavaScript in posts - constructing a compiler that takes an meta-data attribute containing a list of scripts to include and then builds the relevant markup is similarly simple:
> includes::Compiler (Page String) (Page String)
> includes = setWithArrow "include" $ arr $ renderHtml . mapM_ tag . words . getField "include"
> where tag uri = H.script "" ! A.src (toValue uri) ! A.type_ "text/javascript"