nobsun(2007/07/04 10:53:31 JST)
Haskellでもprintfデバッグのようなことをしたいことがある.このとき Debug.Trace モジュールにある trace という関数が便利である.
trace :: String -> a -> a
この関数は値としては第二引数をそのまま返す関数なのだが,その値が評価さ れたときにコンソールに第一引数で与えた文字列を表示するというののである.
たとえば,
add :: Int -> Int -> Int add x y = trace "'add' called" (x + y)
と定義して add 1 (2*3) を評価すると
*Main> 1 + add 2 (3*4) 'add' called 15
となる.
Haskellのプログラミングでは関数適用オペレーター($)を明示的につかって, 処理の連結をおこなうことが良くある.すなわち以下のような断片(この例自 身は特に意味はない)があらわれる.
putStrLn $ show $ lis $ rn $ map read $ words l
これは,「words l の結果のデータが map read に入り,その結果が rn に入 り,その結果が lis に入り,その結果が show に入り,その結果が putStrLn に入る.」というわけである. $ が一種のジョイントとみなせる.そこで, ここを通過するデータをチェックしたいとき用に .$. というオペレーターを 定義しよう.
infixr 0 .$. (.$.) :: Show a => (a -> b) -> a -> b f .$. x = trace (show x) f x
このようにしておくと,$ の代りに .$. を使った場所で通過するデータを見 ることができる.(もちろん通過するデータの型はShowクラスのインスタンス である必要がある.)
putStrLn $ show $ lis .$. rn $ map read $ words l
のように書くと lis に入るデータを見ることができるというわけである.
Haskellプログラミングになれてくると,処理の連結には関数適用オペレーター ($) ではなく関数合成オペレーター (.) になることが普通になる.
getLine >>= putStrLn . show . lis . rn . map read . words
などという断片が多用されるにちがいない.このとき (.) もジョイントのよ うなものだ.そこで (.) を通過するデータを見るためのオペレーター (...) を定義しよう.
infixr 9 ... (...) :: Show b => (b -> c) -> (a -> b) -> (a -> c) f ... g = (f .$.) . g
これで,
getLine >>= putStrLn . show . lis ... rn . map read . words
と書くと rn の結果が lis の入るところでそのデータを見ることができると いうわけである.