GHCと日本語・試行錯誤中

GHC(6.10.4)で日本語を気持ちよく使えるために試行錯誤している。

まず、次のようにコードの先頭に書くと、ちょっと便利

import Prelude hiding (print, putStr, putStrLn)
import System.IO.UTF8

data String' = S' String
instance Show String' where
  show (S' s) = "\"" ++ s ++ "\""
*Main> print ("ほげ", "ふが")
("\12411\12370","\12405\12364")
*Main> print (S' "ほげ", S' "ふが")
("ほげ","ふが")

また、UTF-8エンコーディング以外のファイルは、例えば、次のようにして操作できる:

import Prelude hiding (print, putStr, putStrLn)
import System.IO.UTF8

import qualified Data.ByteString.Lazy as BS
import qualified Data.ByteString.Lazy.UTF8 as BS8
import qualified Codec.Text.IConv as IC

readFile' :: FilePath -> IC.EncodingName -> IO String
readFile' path coding = do
  bs <- BS.readFile path
  return $ BS8.toString $ IC.convert coding "UTF-8" bs

writeFile' :: FilePath -> IC.EncodingName -> String -> IO ()
writeFile' path coding contents =
  BS.writeFile path bs
  where bs = IC.convert "UTF-8" coding $ BS8.fromString contents
*Main> writeFile' "./test.txt" "SHIFT-JIS" "テスト文章\nHaskell 楽しいね?"
*Main> s <- readFile' "./test.txt" "SHIFT-JIS"
*Main> putStrLn s
テスト文章
Haskell 楽しいね?

補足

ちなみに、二つ目のコードは、つぎのようにも書ける:

-- import 省略

readFile' :: FilePath -> IC.EncodingName -> IO String
readFile' path coding =
  fmap (BS8.toString . IC.convert coding "UTF-8") $ BS.readFile path

writeFile' :: FilePath -> IC.EncodingName -> String -> IO ()
writeFile' path coding =
  BS.writeFile path . IC.convert "UTF-8" coding . BS8.fromString

…書けるけど、分かりにくくなっているように思う。

こういう fmap を使ったり、「.」を使って連結したりは、使い方次第でコードがすごく簡潔・直感的になるけど*1、メインの処理の流れを示すためには、むしろ多少冗長なほうが良いのではないだろうか。

*1:僕は、Parsecコンビネータで「n <- fmap read $ digit」としたり、リスト操作関数の中で「filter ((0 /=).fst) l」としたりする。