Skip to content

Instantly share code, notes, and snippets.

@scvalex
Last active December 18, 2015 21:49
Show Gist options
  • Save scvalex/5850193 to your computer and use it in GitHub Desktop.
Save scvalex/5850193 to your computer and use it in GitHub Desktop.
Make strings behave like printf.
{-# LANGUAGE OverloadedStrings, FlexibleInstances, UndecidableInstances #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# OPTIONS_GHC -fno-warn-orphans -fno-warn-type-defaults #-}
module Main where
import Data.String ( IsString(..) )
--------------------
-- Custom printf that takes '%s' for `Show` values.
--------------------
class PrintfType t where
spr ::String -> [SomeShow] -> t
instance PrintfType [Char] where
spr format args = uprintf format (reverse args)
instance PrintfType (IO ()) where
spr format args = do
putStr (uprintf format (reverse args))
instance (Show a, PrintfType r) => PrintfType (a -> r) where
spr format args = \a -> spr format (SomeShow a : args)
data SomeShow = forall a. (Show a) => SomeShow a
uprintf :: String -> [SomeShow] -> String
uprintf "" [] = ""
uprintf "" (_:_) = error "too many arguments; learn to compromise"
uprintf ('%':'%':cs) us = '%' : uprintf cs us
uprintf ('%':_) [] = error "too few arguments; stand up for yourself"
uprintf ('%':'s':cs) (SomeShow n : us) = show n ++ uprintf cs us
uprintf (c:cs) us = c : uprintf cs us
--------------------
-- Strings are printfs.
--------------------
instance (PrintfType a) => IsString a where
fromString s = spr s []
main :: IO ()
main = do
"Foo! %s %s\n" 23 42
@scvalex
Copy link
Author

scvalex commented Jun 25, 2013

The associated blog post is here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment