Haskell でネットワーク

Haskell でネットワークしてみよう,ということで.id:syd_syd さんの http://haskell.g.hatena.ne.jp/syd_syd/20061019/p1 とかのあたりも参考にすればいいと思う!
研究室で定期的に投げられるお知らせメールを自動化しようということで,Python,Ruby,Java,Haskell で同じものを書いた.そのときにはまったこととかをメモ.この記事は id:syd_syd さんによるバックアップのもとに書かれました.

Haskell でどっかのサーバに接続する

そもそもサーバにアクセスするにはどうすればいいのか?以下は Google Calendar の吐く RSS にアクセスするコード.

getGCalXML =
    do urlh <- connectTo gcalServer $ PortNumber 80
       hPutStr urlh $ "GET "++gcalDirectory++"\r\n"
       hFlush urlh
       gcal <- hGetContents urlh
       length gcal `seq` hClose urlh
       hClose urlh
       return gcal

gcalServer は Google Calendar のサーバ名.gcalDirectory は RSSディレクトリ.ポイントは改行を"\r\n"にすることと,忘れずにバッファをフラッシュすることと,seq すること.遅延評価する Haskell では,ファイルディスクリプタに対して hGetContents しても,実際にはデータを読み込まない.そのため,gcal がどこかで必要とされる前に hClose してしまうと,データがとれなくなってしまう.これには30分くらいはまった.アドバイスをいただいた id:syd_syd さんに感謝.
この問題を解決するのが "length gcal `seq` hClose urlh"という式.seq は第一引数を評価してから第二引数を評価する関数.これでファイルディスクリプタを閉じる前にデータを読み出すことができる.length がついてるのは,データの全体を読み込むようにするため.単に gcal の評価を強制しただけだと,データが途中まで読まれない.理由は調べてないけど,gcal を評価するということは,gcal が [] なのか x:xs なのかという違いのみを見るからっぽい.中途半端に読まれるのはたぶんキャッシュの影響とかじゃないかね.
あと, hGetContents は eof がこないと停止しないというやっかいな話もあるので注意.

日本語

putStrLn とかで日本語を出そうとすると文字化けしてしまうが,GHC は日本語も扱うことができる.日本語は適当に UTF8 とかに変換して使おう.変換ライブラリはそのへんにいくつも転がっている.