Lecture #16, Nov. 29, 2004

21
Cse536 Functional Programming 1 03/16/22 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

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

Transcript of Lecture #16, Nov. 29, 2004

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)))