型安全なprintfを書いてみましょう

昨日のあれで引き下げれるかというとそういうわけにもいかないので、Cayenneのpaperの中で触れられていた

http://www.brics.dk/RS/98/12/index.html

を読んでみました。
タイトルは"Formatting Strings in ML"


全然ページ数は無いのですが、今お腹痛いので適当に書き上げただけwww

読んだ時のメモ

Formatting Strings in ML

MLにおいては、printf-likeな関数はつまらないものでは無い。

例えば、
format "%i is %s%n" 3 "x"
において
formatの型は string -> int -> string -> stringである。

では次の時はどうなるだろう。

format "%i / %i" 10 20
この時は
string -> int -> int -> string
となるはずだ。この様なformatをMLでは書く事が出来ない。
formatは、1つの型だけに定められるべきであるからだ。

この問題における重要な点は、formatの型がその最初の引数に寄る所だ。 <- 依存型

実際にHaskell

i_ :: String -> Int -> String
i_ now i = now ++ (show i)

s_ :: String -> String -> String
s_ now s = now ++ s

l_ :: String -> String -> String
l_ s now = now ++ s

o1 a b i = b . (a i)
o2 a b i = b $ (a i)

infixr 5 `o1`
infixr 5 `o2`

format a = a ""

核となるのはこんな感じ。


すげー汚いですが

 *Main> format (i_ `o1` i_ `o1` i_ `o1` l_ "test" `o2` s_) 1 2 3 "hoge"
"123testhoge"
 *Main> format (i_ `o1` i_ `o1` i_ `o1` l_ "test" `o2` s_) 1 2 3 4

<interactive>:1:57:
    No instance for (Num String)
      arising from the literal `4' at <interactive>:1:57
    Possible fix: add an instance declaration for (Num String)
    In the fifth argument of `format', namely `4'
    In the expression:
        format (i_ `o1` i_ `o1` i_ `o1` l_ "test" `o2` s_) 1 2 3 4
    In the definition of `it':
        it = format (i_ `o1` i_ `o1` i_ `o1` l_ "test" `o2` s_) 1 2 3 4

o1とo2分けてる所が気持ち悪い感じですが、分けないでもどうにかなりそうな感じなのでまぁそこまではやんないですけど。


この話の重要な所は、元のpaperでも述べられている様に

The crux of the problem is that 
the type of format depends on the value of its &#64257;rst argument, i.e., the pattern.

という事ですね。

嘘書いてたwww

このDanvy先生のpaperは、continuation festa 2008のTyped printfからも参照されている様に、MLでCPSを用いてtype safeなprintfを実装しましょうという話なので、私が上に書いた奴は皆目見当違いでしたw


トイレからも帰ってきて腹落ち着いたので読み直してから新しく書きます。