Skip to content
Go to file

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


This is my personal website, hosted at It used to be at, but my last name is hard to spell, so I switched to an easier-to-spell domain name.

My website is built with Haskell and runs on top of lighttpd.

Html Generation

Using a State monad, I have been able to write html as Haskell code instead of injecting values into templates:

-- I am using DLists to ensure that string appending is done right assiciatively.
--   (a ++ (b ++ c)) instead of ((a ++ b) ++ c)
-- The IO monad is added as well so that I can do things like cache busting based on the current commit hash
--   (see
type Html = StateT (DList Char) IO ()

uText :: String -> Html
uText str = modify (\x -> x `append` (fromList str))

-- Note that encode encodes unsafe characters.
text :: String -> Html
text = uText . encode

Another nice benefit is that due to the laziness of Haskell, monadic values (like values of the Html type) can be passed around before they are evaluated, allowing you to inject Html values into functions, that can then place those values where appropriate. One common example of this is a tag function:

tag :: String -> [Option] -> Html -> Html
tag name options contents = do
    uText "<" >> uText name >> (mapM renderOption options) >> uText ">"
    uText "</" >> uText name >> uText ">"
    renderOption (key, value) = do
        uText " "
        uText key
        uText "=\""
        uText value
        uText "\""

You can then create a page like this:

examplePage :: Html
examplePage = do
    uText "Content-Type: text/html\n"
    uText "\n"
    uText "<!DOCTYPE html>"
    tag "html" [] $ do
        tag "head" [] $ tag "title" [] $ text "Example Page"
        tag "body" [] $ do
            tag "h1" [] $ text "Example Page"
            tag "p" [] $ text "Hello, world!"

Notice how I never need to take care of closing tags, it is done automatically.

Once again, passing monadic values is very convenient, this time for making templates:

noHtml :: Html
noHtml = return ()

stylesheet :: String -> Html
stylesheet url = do
    tag "link" [("rel", "stylesheet")
               ,("type", "text/css")
               ,("href", url)] noHtml

pageTemplate :: Html -> Html -> Html
pageTemplate head content = do
    uText "Content-Type: text/html\n"
    uText "\n"
    uText "<!DOCTYPE html>"
    tag "html" [] $ do
        tag "head" [] $ do
            stylesheet "my_main_styles.css"
        tag "body" [] $ do
            tag "div" [("class", "container")] content

examplePage :: Html
examplePage =
    pageTemplate head content
    head = tag "title" [] $ text "Example Page"
    content = do
        tag "h1" [] $ text "Example Page"
        tag "p" [] $ text "Hello, world!"


No description, website, or topics provided.



No releases published


No packages published
You can’t perform that action at this time.