PATH_INFOを見てテンプレートを読み込んで表示する
やっと少しだけ分かってきた。
IO a の型は普通の a型 に戻すことは出来ないけれど、do の中ならIOを取ることが出来るのか。
PATH_INFOから templates/ 以下のファイルを読み込むプログラム
-- -- pathinfo test -- import System.Environment contentType = "text/html" templateDir = "templates" main :: IO () main = do pathinfo <- pathInfo res <- parseRequest pathinfo putStr (show res) parseRequest :: String -> IO HTTPResponse parseRequest p = do body <- template p return (HTTPResponse contentType body) template :: String -> IO String template name = catch (readFile $ templatePath name) (const $ return $ templatePath name ++ " not found.\n") templatePath :: String -> String templatePath name = templateDir ++ name ++ ".html" pathInfo :: IO String pathInfo = catch (getEnv "PATH_INFO") (const $ return "") -- エラーの場合は const (return Nothing) (IOError) となる data HTTPResponse = HTTPResponse { header :: String, body :: String } instance Show HTTPResponse where show = httpResponseToString httpResponseToString :: HTTPResponse -> String httpResponseToString (HTTPResponse h b) = concat [ "Content-Type: ", h, "\r\n", "Content-Length: ", show (length b), "\r\n", "\r\n", b ]
ここでは、テンプレートを読み込む関数は readFile を使っているので IO String 型になってしまう。
これを String 型に戻すことは出来ないが、
parseRequest p = do body <- template p
のようにすれば、body はString 型になる。
do の中で使う関数は引数がString型の関数でも問題ない。
という風に作っていくので合ってるのかなぁ。。。いまいち自信がない。
# 追記
template :: String -> IO String template name = catch (readFile $ templatePath name) (const $ return $ templatePath name ++ " not found.\n")
この部分は
template :: String -> IO String template name = catch (readFile $ template) (const $ return $ template ++ " not found.\n") where template = templatePath name
こうするとHaskellっぽくなるのか。
templatePath関数もスコープを限定できるな・・。なるほど。なるほど。