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"関数の解析が終わりました。


今日はここまで!