Download presentation
Presentation is loading. Please wait.
1
Cse536 Functional Programming 1 6/30/2015 Lecture #16, Nov. 29, 2004 Todays Topics – Files, Channels, and Handles –IO exception handling –First Class Channels –Concurrency and ForkIO Reading – Read Chapter 16 – Communicating with the Outside World – Read Chapter 17 – Rendering Reactive Animations Assignment – Last homework assigned Wednesday. See webpage. Due Wednesday Dec. 8, 2004. Final Exam –scheduled for Wednesday Dec. 8, 2004
2
Cse536 Functional Programming 2 6/30/2015 Files and Handles The functions: writeFile :: FilePath -> String -> IO () appendFile :: FilePath -> String -> IO () are used to read and write to files, but they incur quite a bit of overhead if they are used many times in a row. Instead we wish to open a file once, then make many actions on the file before we close it for a final time. openFile :: FilePath -> IOMode -> IO Handle hClose :: Handle -> IO () data IOMode = ReadMode | WriteMode | AppendMode deriving (Eq, Ord, Ix, Bounded, Enum, Read, Show)
3
Cse536 Functional Programming 3 6/30/2015 File Modes A file mode tells how an open file will be used. Different modes support different operations. When in WriteMode hPutChar :: Handle -> Char -> IO () hPutStr :: Handle -> String -> IO () hPutStrLn :: Handle -> String -> IO () hPrint :: Show a => Handle -> a -> IO () When in ReadMode hGetChar :: Handle -> IO Char hGetLine :: Handle -> IO String
4
Cse536 Functional Programming 4 6/30/2015 Standard Channels and Errors Predefined standard Channels stdin, stdout, stderr :: Handle Error Handling while doing IO isEOFError :: IOError -> Bool -- Test if the EOF error ioError :: IOError -> IO a -- Raise an IOError catch :: IO a -> (IOError -> IO a) -> IO a -- Handle an Error Other IO types of errors and their predicates. –isAlreadyExistsError, isDoesNotExistError, –isAlreadyInUseError, isFullError, –isEOFError, isIllegalOperation, –isPermissionError, isUserError,
5
Cse536 Functional Programming 5 6/30/2015 IOError IOError is an abstract datatype – NOT and algebraic datatype, defined with data like [ ] or Tree Thus it does not admit pattern matching. Hence the use of all the IOError recognizing predicates. –isAlreadyExistsError, isDoesNotExistError, –isAlreadyInUseError, isFullError, –isEOFError, isIllegalOperation, –isPermissionError, isUserError This was a concious decision, made to allow easy extension of the kinds of IOErrors, as the system grew.
6
Cse536 Functional Programming 6 6/30/2015 Handling IO Errors Any action of type IO a may potentially cause an IO Error. The function –catch :: IO a -> (IOError -> IO a) -> IO a can be used to gracefully handle such an error by providing a “fix” getChar' :: IO Char getChar' = catch getChar (\ e -> return '\n') getChar2 :: IO Char getChar2 = catch getChar (\ e -> if isEOFError e then return '\n' else ioError e) –- pass non EOF errors on
7
Cse536 Functional Programming 7 6/30/2015 An Example getLine' :: IO String getLine' = catch getLine'' (\ e -> return ("Error: " ++ show e)) where getLine'' = do { c <- getChar2 ; if c == '\n' then return "" else do { l <- getLine' ; return (c:l) }
8
Cse536 Functional Programming 8 6/30/2015 Catching errors when opening files getAndOpenFile :: String -> IOMode -> IO Handle getAndOpenFile prompt mode = do { putStr prompt ; name <- getLine ; catch (openFile name mode) (\e -> do { putStrLn ("Cannot open: "++name) ; print e ; getAndOpenFile prompt mode }) }
9
Cse536 Functional Programming 9 6/30/2015 Copying Files main = do { fromHandle <- getAndOpenFile "Copy from: " ReadMode ; toHandle <- getAndOpenFile "Copy to: " WriteMode ; contents <- hGetContents fromHandle ; hPutStr toHandle contents ; hClose fromHandle ; hClose toHandle ; putStr "Done\n" }
10
Cse536 Functional Programming 10 6/30/2015 First Class Channels A Channel is a special kind of abstraction, in the multiprocessing (or concurrency) paradigm. If you “pull” on the tail of a channel, and it is null, then you “wait” until something becomes available. First Class Channel Operations newChan :: IO (Chan a) writeChan :: Chan a -> a -> IO () readChan :: Chan a -> IO a getChanContents :: Chan a -> IO [a] isEmptyChan :: Chan a -> IO Bool
11
Cse536 Functional Programming 11 6/30/2015 Example ex1 = do { c <- newChan ; writeChan c 'a' ; writeChan c 'b' ; a <- readChan c ; b <- readChan c ; print [a,b] ; return [a,b] } It is easy to cause deadlock Using Channels just flipping the order of the writeChan and the readChan actions will do it
12
Cse536 Functional Programming 12 6/30/2015 Channels are used to communicate Independent (concurrent) processes can communicate through channels. An independent, concurrent process is started in Haskell with the forkIO primitive. forkIO :: IO () -> IO () ex2 :: IO() ex2 = do { c1 <- newChan :: IO(Chan Int) ; c2 <- newChan :: IO(Chan Int) ; forkIO (client c1 c2) ; forkIO (server c2 c1) }
13
Cse536 Functional Programming 13 6/30/2015 Client Server Example from chapt 14 client :: Chan Int -> Chan Int -> IO () client cin cout = do { writeChan cout 1 ; loop } where loop = do { c <- readChan cin ; print c ; writeChan cout c ; loop } server :: Chan Int -> Chan Int -> IO () server cin cout = do loop where loop = do { c <- readChan cin ; writeChan cout (c+1) ; loop }
14
Cse536 Functional Programming 14 6/30/2015 Rendering Reactive Animations To render a reactive animation, we need to connect the stream of real events (mouse clicks, key presses, clock ticks, etc.) to our abstract representation of behaviors as stream transformers. The Goal is to write a function: reactimate :: String -> Behavior a -> (a -> IO Graphic) -> IO () Since a (Behavior a) has form (Beh f) where f is a function with type ([Maybe UserAction],[Time]) -> [a] We need to manufacture a pair of streams with type ([Maybe UserAction],[Time])
15
Cse536 Functional Programming 15 6/30/2015 windowUser We do this with the function: windowUser :: Window -> IO ([Maybe UserAction],[Time],IO ()) Used in the following fashion ((uts,ts),addEvents) <- windowUser w
16
Cse536 Functional Programming 16 6/30/2015 The Channel Abstraction (us,ts,addEvents) <- windowUser w us, and ts are infinite streams made with channels. addEvents :: IO () is a action which adds the latest user actions, thus extending the streams us and ts
17
Cse536 Functional Programming 17 6/30/2015 Reactimate reactimate :: String -> Behavior a -> (a -> IO Graphic) -> IO () reactimate title franProg toGraphic = runGraphics $ do w <- openWindowEx title (Just (0,0)) (Just (xWin,yWin)) drawBufferedGraphic (Just 30) (us,ts,addEvents) <- windowUser w addEvents let drawPic (Just p) = do g <- toGraphic p setGraphic w g addEvents getWindowTick w drawPic Nothing = return () let Event fe = sample `snapshot_` franProg mapM_ drawPic (fe (us,ts))
18
Cse536 Functional Programming 18 6/30/2015 Making a Stream from a Channel makeStream :: IO ([a], a -> IO ()) makeStream = do ch <- newChan contents <- getChanContents ch return (contents, writeChan ch)
19
Cse536 Functional Programming 19 6/30/2015 A Reactive window windowUser :: Window -> IO ([Maybe UserAction], [Time], IO ()) windowUser w = do (evs, addEv) <- makeStream t0 <- timeGetTime let addEvents = let loop rt = do mev <- maybeGetWindowEvent w case mev of Nothing -> return () Just e -> addEv(rt, Just e) >> loop rt in do t <- timeGetTime let rt = w32ToTime (t-t0) loop rt addEv (rt, Nothing) return (map snd evs, map fst evs, addEvents)
20
Cse536 Functional Programming 20 6/30/2015 The “Paddle Ball” Game paddleball vel = walls `over` paddle `over` ball vel walls = let upper = paint blue (translate ( 0,1.7) (rec 4.4 0.05)) left = paint blue (translate (-2.2,0) (rec 0.05 3.4)) right = paint blue (translate ( 2.2,0) (rec 0.05 3.4)) in upper `over` left `over` right paddle = paint red (translate (fst mouse, -1.7) (rec 0.5 0.05)) between x (a,b) = x >* a &&* x <* b
21
Cse536 Functional Programming 21 6/30/2015 The “reactive” ball ball vel = let xvel = vel `stepAccum` xbounce ->> negate xpos = integral xvel xbounce = predicate (xpos >* 2 &&* xvel >* 0 ||* xpos <* -2 &&* xvel <* 0) yvel = vel `stepAccum` ybounce ->> negate ypos = integral yvel roofbounce = ypos >* 1.5 &&* yvel >* 0 paddlebounce = (ypos `between` (-2.0,-1.5)) &&* (fst mouse `between` (xpos-0.25,xpos+0.25)) &&* (yvel <* 0) ybounce = predicate (roofbounce ||* paddlebounce) in (paint yellow (translate (xpos, ypos) (ell 0.2 0.2)))
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.