1 / 12

Chapter 16

Chapter 16. Communicating With the Outside World. Motivation. In Chapter 3 we learned how to do basic IO, but it was fairly limited. In this chapter we investigate advanced IO ideas: file handles, channels, exceptions, and concurrency.

Télécharger la présentation

Chapter 16

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 16 Communicating Withthe Outside World

  2. Motivation • In Chapter 3 we learned how to do basic IO, but it was fairly limited. • In this chapter we investigate advanced IO ideas: file handles, channels, exceptions, and concurrency. • The ideas developed here will be used in the next chapter to write a renderer for FAL. • The ideas will continue to be cast in terms of “IO actions” of type “IO a”, and will be sequenced using Haskell’s “do” syntax. • The “mysteries” underlying the type “IO” and Haskell’s “do” syntax will be revealed in Chapter 18. (Guess what’s underneath it all? Yes, functions! )

  3. File Handles • Recall from Chapter 3 the IO actions: writeFile :: FilePath -> String -> IO () appendFile :: FilePath -> String -> IO () type FilePath = String • These functions open a file, write a string, and then close the file. • But if many successive writes are needed, the repeated openings and closings can be very inefficient. • Better to open a file, and leave it open until done:openFile :: FilePath -> IOMode -> IO Handle hClose :: Handle -> IO () data IOMode = ReadMode | WriteMode | AppendMode | ReadWriteMode

  4. File Operations • Once open, many file operations are possible:hPutChar :: Handle -> Char -> IO ()hPutStr :: Handle -> String -> IO ()hPutStrLn :: Handle -> String -> IO ()hPrint :: Show a => Handle -> a -> IO ()hGetChar :: Handle -> IO CharhGetLine :: Handle -> IO StringhGetContents :: Handle -> String when in “WriteMode” when in “ReadMode”

  5. Standard Channels • As in many OS’s, certain kinds of IO are treated like files. In Haskell these are called channels, and include standard input (stdin), standard output (stdout), and standard error (stderr). • Indeed, these two functions are pre-defined in the Prelude: getChar :: IO Char getChar = hGetChar stdin putChar :: IO () putChar = hPutChar stdout

  6. Exceptions • There are many ways that an IO action might fail, and we need a way to detect and recover from such failures. • In Haskell, IO failures are called exceptions, and they can be “caught” by:catch :: IO a -> (IOError -> IO a) -> IO a • For example: getChar' :: IO Char getChar' = catch getChar (\e -> return '\n')

  7. Dispatching on IOError • IoError is an abstract type with predicates such as: isEOFError :: IOError -> Bool isDoesNotExistError   :: IOError -> Booland a “throw” operation: ioError :: IOError -> IO a • A “more refined” getChar can then be defined: getChar' :: IO Char getChar' = catch getChar (\e -> if isEOFError e then return '\n‘ else ioError e )Note how ioError “throws” the error to an outer dynamic scope. • (See text for example of “nested” exceptions.)

  8. Putting It All Together(copying a file) getAndOpenFile :: String -> IOMode -> IO Handle getAndOpenFile prompt mode =do putStr prompt name <- getLine catch (do handle <- openFile name mode return handle ) (\error -> do putStrLn ("Cannot open " ++ name) print error getAndOpenFile prompt mode ) Main :: IO () main = do fromHandle <- getAndOpenFile "Copy from: " ReadMode toHandle <- getAndOpenFile "Copy to: " WriteMode contents <- hGetContents fromHandle hPutStr toHandle contents hClose fromHandle hClose toHandle putStrLn "Done."

  9. First-Class Channels • “First-class channels” are different from the “standard channels” described earlier. • They are a mechanism through which Haskell “processes” can communicate asynchronously. • A first-class channel containing values of type “a” has type “Chan a”. • The key operations are: newChan :: IO (Chan a) writeChan :: Chan a -> a -> IO () readChan :: Chan a -> IO a getChanContents :: Chan a -> IO [a] isEmptyChan :: Chan a -> IO Bool

  10. Example • A first-class channel implements an unbounded queue that can be written to and read from asynchronously. • For example: do c <- newChan writeChan c `a` writeChan c `b` . . . do . . . a <- readChan c b <- readChan c return [a,b]returns the string "ab".

  11. Concurrency • Concurrent processes may be forked off from the main computation by forkIO :: IO () -> IO () • The IO action: forkIO pwill cause p to run concurrently with the main program. • For example, we can create a concurrent version of the client-server program from Chapter 14.[ see next slide ]

  12. client :: Chan Int -> Chan Int -> IO () client cin cout =do writeChan cout 1 loopwhere loop = do c <- readChan cin print c writeChan cout c loop server :: Chan Int -> Chan Int -> IO () server cin cout =do loopwhere loop = do c <- readChan cin writeChan cout (c+1) loop Concurrent Client-Server main :: IO () main = do c1 <- newChan :: IO (Chan Int) c2 <- newChan :: IO (Chan Int) forkIO (client c1 c2) forkIO (server c2 c1)

More Related