top page > computer > haskell > web_lecture > for_programmer > monoid_log.html
更新日:
文責: 重城良国

ログの記録

(工事中 60%)

はじめに

モノイドの使用例を示す。ここまでの知識だとなかなか適切な例がないのでややこじつけ的な例となる。

関数適用

関数合成しながら値をためていくことを考える。具体的には

を演算の結果以外にためていく例を考えよう。

関数適用のログ

関数を合成するときにログを記録していくことを考える。結果として「ログの文字列」と「演算の結果」がほしい。

処理にかかる時間

関数を適用するときにかかる時間を記録する。結果として「かかる時間」と「演算の結果」がほしい。

共通の枠組み

関数適用のログは文字列を結合していけばいい。処理にかかる時間は整数値を加算していけばいい。これらには型クラスMonoidのクラス関数mappendの枠組みが使える。

monoid_log.hs

モジュールData.Monoidには型クラスMonoidといくつかのインスタンスが定義されている。

import Data.Monoid

型Funはためていく値の型mと(a -> b)型の関数から成る。

data Fun m a b = Fun m (a -> b)

関数applyはFun型の値の持つ関数を値に適用し、ためてきた値とともに返す。

apply :: Fun m a b -> a -> (m, b)
apply (Fun m f) x = (m, f x)

関数dotはFun型の値の持つ関数を関数合成し、ためている値をmappendで結合する。

dot :: Monoid m => Fun m b c -> Fun m a b -> Fun m a c
Fun m f `dot` Fun n g = Fun (m `mappend` n) (f . g)

関数funはふつうの関数を空の値を追加して型Funの値に変換する。

fun :: Monoid m => (a -> b) -> Fun m a b
fun f = Fun mempty f

関数putはふつうの関数にためていく値を追加して型Funの値に変換する。

put :: (a -> b) -> m -> Fun m a b
put f m = Fun m f

ログをとりながら

ログをとりながら演算した結果を文字列として返す。

% ghci monoid_log.hs
*Main> fun show `dot` put (* 2) "double; " `dot` put (+ 3) "add 3; " `apply` 8
("double; add 3; ", "22")

処理速度を計算しながら

かけ算にかかる時間が4で足し算にかかる時間が3だとする。

*Main> fun show `dot` put (* 2) (Sum 4) `dot` put (+ 3) (Sum 3) `apply` 8
(Sum {getSum = 7}, "22")

まとめ

関数合成しながら適用の結果以外に値をためていくという枠組みを型クラスMonoidを利用して抽象化した。ログと処理にかかる時間とでは「値を結合してためていく」という枠組みが共通している。このように抽象的な関数を使うことで共通した性質を持つものをまとめることができる。

「モノイドとは」へもどる 「1から学ぶHaskell」トップへ

正当なCSSです! HTML5 Powered with CSS3 / styling, and Semantics