昨夜書いたプログラムをリファクタリング
前回までと同じくHTTPのGETリクエストを投げるんだけど、ヘッダを追加してみました。
import Network.HTTP import Network.HTTP.Base import Network.URI httpGet2 :: String -> IO (String) httpGet2 url = do mayUri <- return $ parseURI url uri <- case mayUri of Nothing -> error "" Just u -> return u req <- return $ Request { rqURI = uri ,rqMethod = GET ,rqHeaders = [ Header HdrAcceptCharset "Shift_JIS" ,Header HdrAccept "text/plain; charset=UTF-8" ,Header HdrAccept "text/html; charset=UTF-8" ] ,rqBody = "" } result <- simpleHTTP req res <- return $ either (error . show) id result return $ rspBody res
一気に複雑に。でも増えたコードのほとんどはRequestの組み立て部分。
それはそうと、なんとなく「do記法を使ったら負け」みたいな強迫観念を持っているので>>=で書き換えてみました。
httpGet3 :: String -> IO (String) httpGet3 url = (return $ parseURI url) >>= (\mayUri -> case mayUri of Nothing -> error "" Just u -> return u ) >>= (\uri -> return $ Request { rqURI = uri ,rqMethod = GET ,rqHeaders = [ Header HdrAcceptCharset "Shift_JIS" ,Header HdrAccept "text/plain; charset=UTF-8" ,Header HdrAccept "text/html; charset=UTF-8" ] ,rqBody = "" }) >>= simpleHTTP >>= return . either (error . show) id >>= return . rspBody
・・・いまいち。do記法を使いたくないばかりに無名関数を使わないといけなくなったり $ と . が混在したりと、かなり統一感に欠けるコードになってしまいました。
こんなときは関数分割が足りないのだ、とばかりにリファクタリング。
httpGet4 :: String -> IO (String) httpGet4 url = (return . fromJust . parseURI) url >>= return . getRequest' >>= simpleHTTP >>= return . rspBody . (either (error . show) id) where getRequest' :: URI -> Request String getRequest' uri = Request { rqURI = uri ,rqMethod = GET ,rqHeaders = [(Header HdrAcceptCharset "UTF-8") , (Header HdrAccept "text/plain; charset=UTF-8") , (Header HdrAccept "text/html; charset=UTF-8")] ,rqBody = "" }
おお、$が消えた!
ついでに、こっそりMaybeをパターンマッチしてた箇所をData.MaybeのfromJustに置き換えたりムダなreturnをなくしたりして、かなりすっきりさせることが出来ました。
これなら読める。
>>=を使うと引数が消えるので記述がスリムになるのですが、計算の途中で引数が使えないのが困ります。do記法を使えばこの辺りは解消しますが、小さい関数の組み合わせで大きい関数を作っていく、というHaskellの思想(というより関数型言語の思想か?)に沿うなら、単純な機能を持つ関数に切り出して>>=ですっきり書ける工夫をした方がかっこいいと思うのです。。。