Wikiエンジンの開発
13.3 CGIの処理
昨日は"sequence"関数を追跡しました。
"sequence"関数は、たとえば
[Just 1, Just 2, Just 3] -- → Just [1, 2, 3] [IO "ab", IO "cd", IO "ef"] -- → IO ["ab, "cd", "ef"]
という変換をすることが分かりました。
本日は"mapM"関数を見ていきます。
定義を再度掲載します。
mapM :: Monad m => (a -> m b) -> [a] -> m [b] mapM f as = sequence (map f as)
"mapM"関数の第1引数"f"には"mGetEnvPair"関数が束縛されます。
"mapM"関数の第2引数"as"には
names = [ "SERVER_NAME", "SERVER_PORT", "SERVER_SOFTWARE", "SERVER_PROTOCOL", "GATEWAY_INTERFACE", "SCRIPT_NAME", "REQUEST_METHOD", "PATH_INFO", "PATH_TRANSLATED", "CONTENT_TYPE", "CONTENT_LENGTH", "QUERY_STRING", "HTTP_COOKIE", "HTTP_ACCEPT", "REMOTE_HOST", "REMOTE_ADDR", "REMOTE_USER", "AUTH_TYPE", "HTTPS" ]
が束縛されます。
"mGetEnvPair"関数の型はもちろん
mGetEnvPair :: String -> IO String
です。そして"as"の型も当然
names :: [String]
です。
つまり"mapM"関数の型変数"a"、"b"はいずれもStringなわけですね。
"mapM mGetEnvPair"合成関数によって、"names"の各要素はStringからIO Stringに変換され、リストとなります。
この時点では[IO String]型です。
この値に対して"sequence"関数を適用すると、IO [String]型になります。
では"mGetEnvPair"関数を見ていきましょう。
定義はこんな感じ。
mGetEnvPair name = catch (return . Just . (,) name =<< getEnv name) (const $ return Nothing)
なんかお初なものがたくさんありますね。
まず"mGetEnvPair"関数の引数は上で書いた"names"変数の各要素に束縛されます。
ちょっと分解して考えてみよう。
catch (return . Just . (,) name =<< getEnv name) (const $ return Nothing)
まず"catch"関数。なんとなく例外のcatchを連想します。
定義はこちら。
catch :: IO a -> (IOError -> IO a) -> IO a catch = primCatch
う〜ん、どうも本当に例外をキャッチしているようですね。
"primCatch"関数の定義はどこにもありません。
括弧の中のどれかが例外をスルーするのでしょう。
次に"getEnv"関数(これが例外をスルーしそう)。
"getEnv"関数の説明を引用しておきます。
定義はありませんでした。環境依存なところがありますからね。
getEnv var は環境変数 var の 値を返す。
http://www.sampou.org/haskell/report-revised-j/system.html
もし、変数 var が定義されていなければ、 isDoesNotExistError 例外を発生する。
やっぱり例外をスルーしますね。
先の"catch"関数はこれを補足していたんですね。
ちなみに"getEnv"関数の型は
Prelude System> :i getEnv getEnv :: String -> IO String -- Defined in System.Environment
です。単なる環境変数の値(文字列)ではなく、IOモナドの文字列を返します。
このIOモナドの文字列が、"<<="演算子で、左辺に渡ります。
左辺はこんな感じです。
return . Just . (,) name
まず"(,)"はタプルを作るための演算子を関数として使うための表現ですね。
つまり、環境変数の名前と値のタプルをここで作っているわけです。
つまり、
(,) name -- → (環境変数の値, 環境変数名) -- (=<<)演算子によって、「IOモナドの環境変数の値」は「環境変数の値」に変換されます。
となります。
次に"Just"です。
これは関数じゃなくってMaybe型の値コンストラクタです。
単に
Just (環境変数の値, 環境変数名)
というMaybe型の値を作りだします。
そして最後に"return"関数。
Maybe型の"return"関数の定義はこんな感じ。
return = Just
なので、結果として
Just Just (環境変数の値, 環境変数名) Just (環境変数の値, 環境変数名)
となります。簡単な例で確認してみます。
return . Just . (,) "abc" =<< (return "def") return . Just . (,) "abc" (IO "def") return . Just . ("abc", IO "def") return . Just ("abc", IO "def") Just ("abc", IO "def")
環境変数の名前と値(IOモナド)のタプルを作っているわけです。
"mGetEnvPair"の途中ですが、今日はここまで!