The IsString
type-class and the OverloadedStrings
extension were meant to save Haskell programmers from having to type {ByteString,Text}.pack
over and over again, but they can be used in more creative ways as well.
I like to use printf
to format my strings, but I always forget to type the actual printf
call, and just type the format string followed by the arguments.
With OverloadedStrings
, we can treat the format string as a call to printf
. Here’s how:
{-# LANGUAGE OverloadedStrings, FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
import Data.String ( IsString(..) )
import Text.Printf ( PrintfType, printf )
instance (PrintfType a) => IsString a where
fromString s = printf s
main :: IO ()
main = do
let x = 23 :: Int
s = "World!" :: String
"%d. Hello, %s\n" x s
The bit that turns string literals into calls to printf
is the IsString
instance for PrintfType
. The last line shows the process in action.
The downside is that the types of the arguments need to be fixed for this to work, which makes short examples programs look weird, but shouldn’t be a problem for larger programs where the types are fixed anyway.
Another problem is that, like with printf
, we only handle a few primitive types. We can get around this by writing our own printf
which works for any types with Show
instances.