Upload
teagan-obrien
View
16
Download
0
Embed Size (px)
DESCRIPTION
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 - PowerPoint PPT Presentation
Citation preview
Cse536 Functional Programming
104/20/23
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
Cse536 Functional Programming
204/20/23
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)
Cse536 Functional Programming
304/20/23
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
Cse536 Functional Programming
404/20/23
Standard Channels and Errors• Predefined standard Channels
stdin, stdout, stderr :: Handle
• Error Handling while doing IOisEOFError :: IOError -> Bool -- Test if the EOF errorioError :: IOError -> IO a -- Raise an IOErrorcatch :: 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,
Cse536 Functional Programming
504/20/23
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.
Cse536 Functional Programming
604/20/23
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 ChargetChar' = catch getChar (\ e -> return '\n')
getChar2 :: IO ChargetChar2 = catch getChar (\ e -> if isEOFError e then return '\n' else ioError e) –- pass non EOF errors on
Cse536 Functional Programming
704/20/23
An ExamplegetLine' :: 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)
}
}
Cse536 Functional Programming
804/20/23
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
})
}
Cse536 Functional Programming
904/20/23
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"
}
Cse536 Functional Programming
1004/20/23
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
Cse536 Functional Programming
1104/20/23
Exampleex1 =
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 deadlockUsing Channels
just flipping the order of thewriteChan and the readChan
actions will do it
Cse536 Functional Programming
1204/20/23
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) }
Cse536 Functional Programming
1304/20/23
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 }
Cse536 Functional Programming
1404/20/23
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])
Cse536 Functional Programming
1504/20/23
windowUser
• We do this with the function:
windowUser :: Window ->
IO ([Maybe UserAction],[Time],IO ())
Used in the following fashion
((uts,ts),addEvents) <- windowUser w
Cse536 Functional Programming
1604/20/23
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
Cse536 Functional Programming
1704/20/23
Reactimatereactimate :: 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))
Cse536 Functional Programming
1804/20/23
Making a Stream from a Channel
makeStream :: IO ([a], a -> IO ())
makeStream = do
ch <- newChan
contents <- getChanContents ch
return (contents, writeChan ch)
Cse536 Functional Programming
1904/20/23
A Reactive windowwindowUser :: 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)
Cse536 Functional Programming
2004/20/23
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
Cse536 Functional Programming
2104/20/23
The “reactive” ballball 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)))