型とかちゃんとみるprintf

そんなんできるのか、と思ってたけど分かってしまえば簡単…なのか?

import Numeric (showHex)

type Format a b = (String -> a) -> String -> b

format :: Format String a -> a
format f = f id ""

q :: String -> Format a a
q x = q'
    where q' k s = k (s ++ x)

str :: Format a (String -> a)
str k s x = k (s ++ x)

int :: Format a (Int -> a)
int k s n = k (s ++ show n)

hex :: Format a (Int -> a)
hex k s n = k (s ++ showHex n "")

(&) :: Format b c -> Format a b -> Format a c
f & f' = f''
    where f'' k s = f (\s' -> f' k s') s

こんな風に。

main = do
    putStr "name: "
    name <- getLine
    putStr "num: "
    num <- readLn
    putStrLn $ format (q"Hello, " & str & q"! " & int & q" = 0x" & hex) name num num

さらに

(%) = (&)
s   = str
d   = int
x   = hex
(!) = flip (flip (%) . q)

とすれば

    putStrLn $ format (q"Hello, " %s !"! " %d !" = 0x" %x) name num num

とできてprintfっぽい(かも)。
文字列にqを適用するのが面倒なので(リテラルはそのままでフォーマッタになってほしい)

{-# OPTIONS_GHC -fglasgow-exts #-}

-- ...

class ToF a where
    toF :: a -> Format b c

instance ToF String where
    toF = q

instance ToF (Format a b) where
    toF = id

としたかったんだけどエラーが出るなあ。(toFa,b,cに依存が出てしまうのが問題?よくわからない)