純粋関数的 Haskell I/O プログラミング
HaskellはIOモナドを使えるので命令的Haskellプログラミングが可能になっているのだが,その代償としてプログラム全体の型は自明なIO ()に潰れてしまう.
プログラム全体の型が潰れないような仕組みを考えたのがoiパッケージ.以下は純粋に関数的にプログラムを構成したものである。(もちろん実際には、Haskellのプログラムとして起動するために、main :: IO () が必要であるし、実際の入出力を行うためのプリミティブ関数を構成するにはIOモナドが必要ではある。)
{-# LANGUAGE TypeOperators #-} module Main where import Data.OI import Control.Parallel import System.Environment pmain :: (FilePath,FilePath) -> (FilePath,FilePath) -> ((String, [String], ()), (String, [String], ())) :-> () pmain (kbd1,scr1) (kbd2,scr2) = uncurry par . (talk "Alice" (kbd1,scr1) |><| talk "Bob" (kbd2,scr2)) talk :: String -- 名前 -> (FilePath,FilePath) -- (キーボード, 端末スクリーン) -> [String] -- 相手からのメッセージ列 -> OI (String,[String],()) -- 神託 (キーボード入力列,マージされたメッセージ列,プロセス結果) -> ([String],()) -- (相手へのメッセージ列,プロセス結果) talk name (kbd,scr) msg r = (ins,showscr scr (mergeOI ins msg os) us) where (is,os,us) = deTriple r ins = map ((name ++ ": ")++) $ lines $ readkbd kbd is ---------- main :: IO () main = do { kbd1:scr1:kbd2:scr2:_ <- getArgs ; run $ pmain (kbd1,scr1) (kbd2,scr2) } readkbd :: FilePath -> String :-> String readkbd = iooi . readFile showscr :: FilePath -> [String] -> () :-> () showscr s = iooi . writeFile s . unlines