Scaffolding a Blog Post

Posted on December 26, 2019 by Riccardo
Functional ProgrammingHaskellScript

It’s been two months since the last post. I had a chance to learn a lot of cool stuff that I cannot wait to share! But let’s start with something eazy.

Today, we are going to take a look at a short script written in Haskell with a simple goal in mind: scaffolding a new file with an empty frontmatter, ready to house a new blog post (including this one!).

Hopefully, this will also show how nice it is to use Haskell even in a simple case. Including how helpful is to have a strong type system holding our hands in the process.

We won’t be covering the specifics of the Stack script interpreter. That has been already covered in “Scripting in Haskell and PureScript”.

Suffice to say we need to have an executable file (i.e. chmod +x file.hs) and the following at the top of the file:

#!/usr/bin/env stack
{- stack
  --resolver lts-14.17
  --package some-package
  --package some-other-package

With that in place, ./file.hs is enough to execute the script.

But let’s dive right in the scaffolding one:

main :: IO ()
main = do
  today <- formatTime defaultTimeLocale "%F" <$> getCurrentTime
  --                                             ^ Get the current UTCTime from the system clock.
  --       ^ Format time to yyyy-mm-dd.
  let fileName = fold ["posts", "/", today, "-"]
  --             ^ Fold strings to a single one. `fold` does so by combining the elements of a
  --               structure using a monoid. String is an alias for [Char], the Monoid instance
  --               for [a] uses `<>` to combine `a`s together. In turn `<>` comes from Semigroup.
  --               The Semigroup instance for [a] defines `<>` as `++`.
  --               Therefore, `fileName` is the concatenation of the strings in the list.
  fileExist <- doesFileExist fileName
  when fileExist $ error "file already exists"
  --   ^ If it already exists..
  --               ^ ..stop execution and display an error message..
  writeFile fileName frontmatter
  -- ..otherwise write `frontmatter` to a file at path `fileName`.

And frontmatter is an empty frontmatter ready to be filled:

frontmatter :: String
frontmatter = unlines
  --          ^ An inverse operation to `lines`. It joins lines,
  --            after appending a terminating newline to each.
  [ "---"
  , "title:"
  , "description:"
  , "author:"
  , "cover_image:"
  , "tags:"
  , "  - FunctionalProgramming"
  , "---"

The whole script can be found on Github.

Support my work by tweeting this article! 🙏