Format All The Things!

Haskell has a nice type-safe formatting library called formatting. Underlying it is a bunch of interesting category theory that you don’t need to know to use the library. It takes advantage of the OverloadedStrings extension to allow you to write something like this:

{-# LANGUAGE OverloadedStrings #-}
module Main where

import Formatting
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Data.Text.Lazy as TL

who :: T.Text
who = "world"

main :: IO ()
main = T.putStrLn $ TL.toStrict $ format ("Hello, " % stext % "!") who

Note that using the formatting with the API is a little awkward. We can improve it by using sformat:

main = T.putStrLn $ sformat ("Hello, " % stext % "!") who

We can improve it further by using the function fprintLn supplied by the formatting package:

main = fprintLn ("Hello, " % stext % "!") who

I recently added a nice combinator to make it easier to add formatting to other APIs. It’s always possible to write a function like fprintLn above, but if you have a lot of functions that are expecting a text value (like logging at different levels), it would be a pain to write a formatted version of each of them. I wrote a formatted combinator that’s really easy to use:

main = formatted T.putStrLn ("Hello, " % stext % "!") who

If you’re doing a lot of formatting, it may make sense to define a specific function, but it’s nice to be able to just drop in formatting somewhere with an additional keyword.