Skip to content

Instantly share code, notes, and snippets.

@scvalex
Last active Dec 18, 2015
Embed
What would you like to do?
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

This comment has been minimized.

Copy link
Owner Author

@scvalex 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