もう一回

今度はCPS(Continuation Passing Style)使って書いてみましょうというお話。


正直なところ
http://pllab.is.ocha.ac.jp/~asai/papers/contfest08slide.pdf
Continuation Festa 08でもあったTyping Printfみた方が良いです。


元のMLのを見てみると
例えば

fun lit x k s = k (s ^ x)

において、xは文字列リテラルとして扱いたい引数、kがcontinuation、sはここまでで累積された文字列を表しているようですが、CPS使うんだったらsとかいらねーんじゃ無いかと思って私が適当にでっち上げたのがこれ

lit :: String -> (String -> a) -> a
lit x cont = cont x

int :: (String -> a) -> Int -> a
int cont x = cont $ show (x::Int)

str :: (String -> a) -> String -> a
str cont x = cont x

oo p1 p2 cont = p1 (\x -> p2 (\y -> cont (x ++ y)))

printf pattern = pattern id

とかこんなんで

printf (int `oo` lit "/" `oo` int) 1 2
"1/2"

printf (int `oo` lit " is " `oo` str) 1 "one"
"1 is one"

出来ました。
当然コンパイル時にerrorも吐いてくれます

main = putStrLn $ printf (int `oo` str `oo` int `oo` str) 1 2 3 4

    No instance for (Num String)
      arising from the literal `2' at impl3.hs:17:60
    Possible fix: add an instance declaration for (Num String)
    In the third argument of `printf', namely `2'
    In the second argument of `($)', namely
        `printf (int `oo` str `oo` int `oo` str) 1 2 3 4'
    In the expression:
          putStrLn $ printf (int `oo` str `oo` int `oo` str) 1 2 3 4