Wikiエンジンの開発
13.3 CGIの処理
本日は"reduce"関数です。
定義はこんな感じ。
reduce :: Config -> (String, Config) reduce kvs = (category . fst . head $ kvs, map (\(k,v) -> (itemname k, v)) kvs)
ちょっと複雑です。一つ一つ見ていきます。
その前に、"reduce"関数の引数は、グループ分けされた"Config"型データです。
こんな感じのデータです。
[("database.director", "var"), ("database.encoding", "euc-jp")] -- や [("template.directory", "template")] -- や [("urlmapper.cgiurl", "./"), ("urlmapper.rewrite", "False")]
なんとな〜くですが、この"reduce"関数、
ラベル名(タプルの左要素)のカテゴリ名を抜き出す関数じゃないでしょうか?
例えばこんな感じに変換します。
[("database.director", "var"), ("database.encoding", "euc-jp")] -- は ("database", [("director", "var"), ("encoding", "euc-jp")] -- と変換される。
あくまで予想です。では解析始めます。
まずは"itemname"関数。定義はこんな感じ。
itemname = tail . snd . break (== '.')
なるほど、そのままですね。
ちなみにコメントに
-- a key of the config item = "category.itemname"
とありました。
"category.itemname"の右側"itemname"を取得するわけですね。
でも初めて見る関数があります。
"snd"関数です。
ちょっと気になるので見てみます。
snd :: (a,b) -> b snd (x,y) = y
あぁ、勘違いしていました。
"send"の"snd"じゃなくて、"second"の"snd"なんですね。
タプルの右側要素を取得する関数です。
ということで"itemname"関数を手動で展開してみます。
引数は"category.itemname"とします。
itemname "category.itemname" tail . snd . break (== '.') "category.itemname" tail . snd ("category", ".itemname") tail ".itemname" "itemname"
なるほど、単純に"itemname"のgetterなわけですね。
では次です。
map (\(k,v) -> (itemname k, v)) kvs
これは"reduce"関数の引数であるConfig型データの要素一つ一つに対して、
"category"を取り除く処理です。
こんな感じになります。
[("database.director", "var"), ("database.encoding", "euc-jp")] -- は [("director", "var"), ("encoding", "euc-jp")] [("template.directory", "template")] -- は [("directory", "template")] [("urlmapper.cgiurl", "./"), ("urlmapper.rewrite", "False")] -- は [("cgiurl", "./"), ("rewrite", "False")]
さて"reduce"関数の続きです。
category . fst . head $ kvs,
これはタプルの左側要素となる部分です。
全ての既出の関数ですね。
"head"関数はリストの第一要素を取り出します。
"fst"関数はタプルの左側要素、"category"関数は"category.itemname"の"category"を取り出します。
手動で展開してみます。
category .fst .head $ [("database.director", "var"), ("database.encoding", "euc-jp")] category . fst ("database.director", "var") category "database.director" "director"
やっぱり予想通りでしたね。
"reduce"関数は、Config型データの各要素を以下のように変換する関数です。
("category.itemname", "value") -- を "category", ("itemname", "value") -- に変換する。
これで"parseConfigFile"関数は全て解析出来ました。
この戻り値を"return"関数でIOモナド化するのが"loadConfig"関数です。
ようやく"loadConfig"関数の解析が終わりました。
今日はここまで!