Skip to content

Instantly share code, notes, and snippets.

@nonowarn
Created December 24, 2009 02:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nonowarn/262978 to your computer and use it in GitHub Desktop.
Save nonowarn/262978 to your computer and use it in GitHub Desktop.
StringIO but in Haskell (on GHC-6.12)
=
GHC 6.12 の Unicode I/O
Yusaku Hashimoto
<nonowarn@gmail.com>
-
自己紹介
-
京都の組み込み系専門学生の
皮をかぶった Haskeller
-
ふだんは
nwn とか nonowarn とか
-
本題
-
Unicode I/O
-
Char は Unicode をカバー
-
だけど ascii の範囲を超える文字を
入出力しようとすると化けてた (<= 6.10.*)
-
6.12 から Unicode を
ちゃんと扱えるようになる
=
do
fh <- openFile
"a_file.txt" WriteMode
hPutStrLn fh "〄"
hClose fh
=
-- いやこれでもいいけど
writeFile "a_file.txt" "〄"
-
デフォルトは
Locale の Encoding を使う
=
$ LANG=C ghci
=
それぞれの Handle が
エンコーダ/デコーダを
持つようになった
=
例題:
Shift-JIS で読んで
EUC-JP で出力
=
import System.IO
main = do
sjis <- mkTextEncoding "SHIFT-JIS"
euc <- mkTextEncoding "EUC-JP"
hSetEncoding stdin sjis
hSetEncoding stdout euc
interact id
-
TextEncoding は
Encoder と Decoder のペア
=
mkTextEncoding
:: String -> IO TextEncoding
hSetEncoding
:: Handle -> Encoding -> IO ()
-
Handle を使って入力/出力すると
デコーダ/エンコーダが動く
=
注意:
mkTextEncoding の実装は iconv
=
自前で書くのもあり
ghc -e
':i GHC.IO.Encoding.TextEncoding'
-
もう一個重要な変更点
(Unicode からは離れるが)
-
Handle が FD 以外の
デバイスを持てるようになった
-
Handle
-
Handle of FD
=
Handle <=> Char
FD <=> バイト列
-
<= 6.10
=
Handle <=> Char
~~~~~~~~~~~~~~
FD <=> バイト列
-
>= 6.12
=
Handle <=> Char
[TextEncoding]
FD <=> バイト列
=
Handle <=> Char
[TextEncoding]
*Any* <=> バイト列
-
ファイル以外の物を
Handle を通して扱える
-
3 Steps
=
data MyIO = ...
instance BufferedIO MyIO
instance IODevice MyIO
mkMyIO :: IO Handle
mkMyIO = mkFileHandle
(MyIO ...) ...
=
例:
StringIO
-
まとめ
-
Handle おもしろいよー
-
Simon Marlow さんありがとう
-
以上
module StringIO where
import Prelude hiding (read)
import Foreign
import Foreign.ForeignPtr
import Foreign.C.Types
import GHC.IO.Handle
import GHC.IO.Buffer
import GHC.IO.BufferedIO
import GHC.IO.Device
import Control.Applicative
import Data.Typeable
import Data.Word
import Data.IORef
import System.IO
data StringIOBuffer = StringIOBuffer (IORef [Word8])
deriving (Typeable)
instance RawIO StringIOBuffer where
read (StringIOBuffer ref) ptr len = do
(w,rest) <- fmap (splitAt len) $ readIORef ref
pokeArray ptr w
writeIORef ref rest
return $ length w
readNonBlocking buf ptr len = -- TODO
fmap Just $ read buf ptr len
write (StringIOBuffer ref) ptr len = do
r <- peekArray len ptr
modifyIORef ref (++r)
writeNonBlocking buf ptr len =
write buf ptr len >> return len -- TODO
instance BufferedIO StringIOBuffer where
newBuffer (StringIOBuffer ref) state = do
let buf_len = 1024
buf_ptr <- mallocForeignPtrBytes buf_len
return (emptyBuffer buf_ptr buf_len state)
fillReadBuffer = readBuf
fillReadBuffer0 = readBufNonBlocking
flushWriteBuffer = writeBuf
flushWriteBuffer0 = writeBufNonBlocking
instance IODevice StringIOBuffer where
ready _ _ _ = return True
close _ = return ()
devType _ = return RawDevice
makeStringIO :: IO Handle
makeStringIO = do
buffer <- StringIOBuffer <$> newIORef []
mkFileHandle buffer "string io" ReadWriteMode (Just localeEncoding) nativeNewlineMode
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment