2006-09-08
■ HaskellのモナドIO(つづき)
Action モジュール
module Action (Action, Handle -- 型構成子のみエクスポート
,Mode(..) -- 型構成子,データ構成子ともにエクスポート
,run,exec,eval,initialWorld
,openFile,hClose,hGetChar,hPutChar
,hIsEOF,hGetString,hPutString
) where
-- Action 駆動関数および合成関数 ---------------------------------------
newtype Action a = Act (World -> (a, World))
run :: Action a -> World -> (a,World)
run (Act a) w = a w
exec :: Action a -> World -> World
exec = (snd .) . run
eval :: Action a -> World -> a
eval = (fst .) . run
unit :: a -> Action a
unit x = Act (\ w -> (x,w))
(>=>) :: Action a -> (a -> Action b) -> Action b
(Act a) >=> f = Act (\ w -> let (x,w') = a w in run (f x) w')
(>->) :: Action a -> Action b -> Action b
a >-> b = a >=> const b
-- Monad インスタンス宣言 ----------------------------------------------
instance Monad Action where
return = unit
(>>=) = (>=>)
-- 具体的なアクション --------------------------------------------------
data Mode = R | W | A deriving Show
openFile :: Mode -> Action Handle
hClose :: Handle -> Action ()
hGetChar :: Handle -> Action Char
hPutChar :: Handle -> Char -> Action ()
hIsEOF :: Handle -> Action Bool
hGetString :: Handle -> Action String
hGetString h = hIsEOF h >>= \ eof ->
if eof then return ""
else hGetChar h >>= \ c ->
hGetString h >>= \ cs ->
return (c:cs)
hPutString :: Handle -> String -> Action ()
hPutString h "" = return ()
hPutString h (c:cs) = hPutChar h c >> hPutString h cs
-- World の実装および World を参照する API の実装 ------------------
type World = File
type File = Handle
type Handle = (Stat,Contents)
data Stat = Closed | Opened Mode deriving Show
type Contents = ([Char],[Char])
openFile m = getWorld >>= \ f@(s,(c1,c2)) ->
case s of
(Opened _) -> error "File is busy"
_ -> let f' = (Opened m, cs')
cs' = case m of
R -> (c1,c2)
W -> ([],[])
A -> (foldl (flip (:)) c1 c2, [])
in putWorld f' >> return f'
hClose _ = getWorld >>= \ f@(s,(c1,c2)) ->
let f' = (Closed, ([],foldl (flip (:)) c2 c1))
in putWorld f' >> return ()
hIsEOF _ = getWorld >>= \ f@(s,(c1,c2)) ->
case s of
Closed -> error "file is closed"
_ -> return (null c2)
hGetChar _ = getWorld >>= \ f@(s,(c1,c2)) ->
case s of
Closed -> error "file is closed"
Opened W -> error "file is opened for writing"
_ -> case c2 of
[] -> error "EOF is detected"
c:cs -> let f' = (s,(c:c1,cs))
in putWorld f' >> return c
hPutChar _ c = getWorld >>= \ f@(s,(c1,c2)) ->
case s of
Closed -> error "file is closed"
Opened R -> error "file is opened for reading"
_ -> let f' = (s,(c:c1,c2))
in putWorld f' >> return ()
-- World の直接参照と更新 ----------------------------------------------
getWorld :: Action World
getWorld = Act (\ w -> (w,w))
putWorld :: World -> Action ()
putWorld w = Act (\_ -> ((),w))
initialWorld :: World -- 世界の始まり
initialWorld = (Closed, ([],[]))
世界は一つのファイルのみから構成されていて,Actionを使って,これにを読み書きする.世界の始まりには空のファイルがある.
アクションの実行をシミュレートする
import Action
import Data.Char
mainAction :: Action ()
mainAction = do hw <- openFile W -- ファイルオープン
hPutString hw "hello, haskell." -- ファイルに書き出し
hClose hw -- ファイルクローズ
hr <- openFile R -- ファイルオープン
str1 <- hGetString hr -- ファイルから読み込み
hClose hr -- ファイルクローズ
ha <- openFile A -- ファイルオープン
hPutString ha (capitalize ha) -- ファイルに追加
hClose ha -- ファイルクローズ
capitalize :: String -> String
capitalize = unwords . map cap . words
where cap "" = ""
cap (c:cs) = toUpper c:cs
mainAction がプログラムのエントリポイントである.これを実行してみよう.
*Main> run mainAction initialWorld
((),(Closed,("","hello, haskell.Hello, Haskell.")))
結果はタプルである,第一要素は内側から見たプログラムの値,すなわち ().
第二要素は,アクション実行後の世界の値,すなわち File の値(クローズ状態,
中身("","hello, haskell.Hello, Haskell."))である.
main :: IO ()
で,Haskell の main :: IO () と上の mainAction :: Action () が対応していると見るわけである.
mainAction :: Action () を「実行」するということは,
run mainAction initialWorld
を評価することであった.つまり,mainAction だけを評価しても何も起こらないのである.この傳でいくと Haskell において,プログラムのエントリポイントは main であるが,プログラムの「実行」は main :: IO () を評価することではないということになる.IOモナドを評価しても何もおこらないのである.Haskellでは処理系が run にあたるものを main に適用し,それを評価することで「実行」されるということだろう.
- IO * はアクションを表す値にすぎない.
- IO * を評価しても入出力は「実行」されない.
- return や (>>=) はアクションを生成したり,結合する糊として使える.
- return や (>>=) が入出力の「実行」を司さどるわけではない.
というわけなんだね.
Wan2012/12/20 19:35It's a joy to find smoenoe who can think like that
fzdhbikuvmg2012/12/21 14:27vRcISP <a href="http://fqnhzhjrizya.com/">fqnhzhjrizya</a>
sosqkjc2012/12/21 23:00ozNcCu , [url=http://ikiafqwobwbl.com/]ikiafqwobwbl[/url], [link=http://fgkwwwfcfgkc.com/]fgkwwwfcfgkc[/link], http://sqcfiwuebhng.com/
hlinqiiazvv2012/12/23 08:25eaHUSF , [url=http://pwjwmdlfasjr.com/]pwjwmdlfasjr[/url], [link=http://yqmhlvjsgbhd.com/]yqmhlvjsgbhd[/link], http://fpxbkoptslbg.com/