Text.Printf.printf を使ってみる

Text.PrintfC言語のprintfライブラリに機能が似た関数で引数の数もC言語のprintfと同じように変化させることが出来ます。

最初の例では文字列に含まれる %s、%d 、%.10f が引数の値が展開される部分です。
3箇所%で指定してあり、3個の引数が渡されています。

> :m Text.Printf
> printf "string:%s Integer:%d Float:%.10f\n" "Hello" 123 pi
  -- > string:Hello Integer:123 Float:3.1415926536

printf は 書式を指定するためのString と PrintfType を引数にとります。

> :t printf
printf :: (PrintfType r) => String -> r

> :t printf "%02d\n" 
printf "%02d\n" :: PrintfType r => r

> :t printf "%02d\n" 123
printf "%02d\n" 123 :: PrintfType t => t

printf は IO として扱われると文字列を出力し、Stringとして扱われるとStringを返し、関数として扱われると引数をとる関数になります。

> :m Text.Printf
-- IO として扱う。
> printf "%s %d %.10f\n" "Hello" 123 pi::IO()
         -- > Hello 123 3.1415926536

> let io = printf "%s %d %.10f\n" "Hello" 123 pi::IO()
> :t io  -- > io :: IO ()
> io     -- > Hello 123 3.1415926536

-- Stringとして扱う。
> let str = printf "%s %d %.10f\n" "Hello" 123 pi::String
> :t str  -- > str :: String
> str     -- > "Hello 123 3.1415926536\n"

-- 関数として扱う。
> let func = printf "%s %d %.10f\n" ::(String -> Integer -> Float -> String)
> :t func
func :: String -> Integer -> Float -> String

> func "Hello" 123 pi          -- > "Hello 123 3.1415927000\n"
> putStr $ func "Hello" 123 pi -- > Hello 123 3.1415927000

一番の欠点は書式を文字列で指定しているためにコンパイル時にエラーが検出されないこと。
以下の例では実行して初めて例外が発生しています。

>  printf "%d %d %.10f\n" "Hello" 123 pi::IO()
*** Exception: Printf.printf: bad argument
    -      left adjust (default is right adjust)
    +      always use a sign (+ or -) for signed conversions
    0      pad with zeroes rather than spaces

参考---動作原理が説明されているが、よく分からない・・・Orz