CS223 5/17/2010 Lecture 19 IO in Haskell ============= [RWH, Chapter 7: I/O, p. 165] Actions that return a value dependent on the state of the World and may change the World in the process. type IO a " = World -> (a, World)" Some basic actions getChar :: IO Char -- input a character putChar :: Char -> IO () -- output a character return :: a -> IO a -- trivial action returning a The return function allows us to go from values to actions. Once we are dealing with actions, there is no way back! Note that IO is a primitive tycon. It is not in fact an abbreviation for a function type, and we can't apply values of IO types. Also, instreams are implicit, not explicit. Basic operations: Input: getChar :: IO Char getLine :: IO String getContents :: IO string interact :: (String -> String) -> IO a readIO :: Read a => String -> IO a readLn :: Read a => IO a Output: putChar :: Char -> IO () putStr :: String -> IO () putStrLn :: string -> IO () print :: Show a => a -> IO () Sequencing (Chaining actions) ----------------------------- (>>=) :: IO a -> (a -> IO b) -> IO b Here is a pseudo-definition: act >>= f = \world -> case act world of (v, world') -> f v world' There is another sequencing function, >> which represents a special case where the second action is independent of the result of the first: (>>) :: IO a -> IO b -> IO b act1 >> act2 = \world -> case act1 world of (_, world') -> act2 world' We can easily defined >> in terms of >>= : act1 >> act2 = act1 >>= (\_ -> act2) ----------------------------- The do notation act1 >>= (\v1 -> act2 >>= (\v2 -> act3)) can also be written do v1 <- act1 act1 >>= (\v1 -> ...) v2 <- act2 act2 >>= (\v2 -> ...) act3 act3 >> (...) v3 <- act4 act5 as though it was a sequence of imperative assignment statments. But these are not assignment statements but variable bindings. Examples: getLine :: IO string getLine = do c <- getChar if c == '/n' then return "" else do s <- getLine return (c:s) ------------------------------------------------------- Exercise: translate these definitions into conventional Haskell notation using >>= and >>. ------------------------------------------------------- reverse2lines :: IO () reverse2lines = do line1 <- getLine line2 <- getLine putStrLn (reverse line2) putStrLn (reverse line1) reverse2lines :: IO () reverse2lines = do line1 <- getLine line2 <- getLine let rev1 = reverse line1 let rev2 = reverse line2 putStrLn rev2 putStrLn rev1 while :: IO Bool -> IO () -> IO () while test action = do res <- test if res then do action while test action else return () copyInputToOutput :: IO () copyInputToOutput = while (do res <- isEOF return (not res)) (do line <- getLine putStrLn line) An example with simple file I/O: (readFile and writeFile take simple strings to designate the files on which I/O is to be performed. More sophisticated file I/O uses file "handles".) main = do putStr "Input file: " ifile <- getLine putStr "Output file: " ofile <- getLine s <- readFile ifile writeFile ofile (filter isAscii s) putStr "Filtering successful\n"