eecs 700 functional programming - ittc.ku.eduandygill/teaching/2010/eecs700/slides12.pdf ·...

Post on 07-Jul-2020

4 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

EECS 700Functional Programming

Dr. Andy Gill

University of Kansas

April 1, 2010

1 / 27

IO and Haskell

Only things that return an IO

can do IO.

2 / 27

IO and Polymorphism

A polymorphic argument can returnanything , so can be used to constructan IO, but only if someone else providesthe construction of the polymorphicargument.

3 / 27

> :t foldr(a -> b -> b) -> b -> [a] -> blet put str more = putStrLn str >> more*Main> :t putput :: String -> IO b -> IO b> :t foldr put (return ()) (words "Hello World")IO ()> foldr put (return ()) (words "Hello World")HelloWorld>

foldr helped build the IO command,but did not actually execute the IO actions directly.

4 / 27

> :t [ putStrLn (show n) | n <- [1..10]][ putStrLn (show n) | n <- [1..10]] :: [IO ()]> [ putStrLn (show n) | n <- [1..10]]<interactive>:1:0:

No instance for (Show (IO ()))arising from a use of ‘print’ at <interactive>:1:0-34

Possible fix: add an instance declaration for (Show (IO ()))In a stmt of a ’do’ expression: print it

>:t sequencesequence :: (Monad m) => [m a] -> m [a]> sequence [ putStrLn (show n) | n <- [1..10]]123...10[(),(),(),(),(),(),(),(),(),()]> :t sequence_sequence_ :: (Monad m) => [m a] -> m ()

5 / 27

File IO in Haskell

import Data.Char

main = dostr <- readFile "Example.hs"let str’ = map toUpper strwriteFile "outfile" str’

IMPORT DATA.CHAR

MAIN = DO

STR <- READFILE "EXAMPLE.HS"

LET STR’ = MAP TOUPPER STR

WRITEFILE "OUTFILE" STR’

6 / 27

import Data.Charimport System.IO

main = doin_h <- openFile "Example2.hs" ReadModeout_h <- openFile "outfile2" WriteModeloop $ do str <- hGetLine in_h

hPutStrLn out_h (map toUpper str)

loop m = m >> loop m

$ ./Example2Example2: Example.hs: hGetLine: end of file

7 / 27

import Data.Charimport System.IO

main = doin_h <- openFile "Example2.hs" ReadModeout_h <- openFile "outfile2" WriteModelet loop = do

eof <- hIsEOF in_hif eofthen return ()else do str <- hGetLine in_h

hPutStrLn out_h (map toUpper str)loop

loophClose in_hhClose out_h

8 / 27

IO Style Exceptions in Haskell

-- inside System.IO.Error

catch :: IO a -> (IOError -> IO a) -> IO a

ioError :: IOError -> IO a

isEOFError :: IOError -> Bool...

9 / 27

Asynchronous Exceptions in Haskell

-- inside Control.Exception (in ghc 6.10)

catch :: Exception e => IO a -> (e -> IO a) -> IO a

throw :: Exception e => e -> a -- no IO monad!throwIO :: Exception e => e -> IO a...

10 / 27

Asynchronous Exceptions in Haskell (continued)

import Control.Exception as E

main = do(if 99 ‘div‘ 0 == 4

then print "Hello"else print "World")

‘E.catch‘ (\ e -> print $ "Caught Problem: "++ show (e :: SomeException))

> main"Caught Problem: divide by zero">

11 / 27

Laziness and Asynchronous Exceptions

import Control.Exception as E

example = do(return (99 ‘div‘ 0 == 4))

‘E.catch‘ (\ e -> do print $ "Caught Problem: "++ show (e :: SomeException)

return False)

> example*** Exception: divide by zero>

12 / 27

Laziness and Asynchronous Exceptions

import Control.Exception as E

example = do(return (99 ‘div‘ 0 == 4) >>= \ v -> evaluate v)

‘E.catch‘ (\ e -> do print $ "Caught Problem: "++ show (e :: SomeException)

return False)

> example"Caught Problem: divide by zero">

13 / 27

Strange Function

-- inside Control.Exception (in ghc 6.10)

throwTo :: Exception e => ThreadId -> e -> IO ()

What does this mean? Can Haskell have many IO threads running?

14 / 27

Forking Threads

-- inside Control.Concurrent

forkIO :: IO () -> IO ThreadId

-- alsothreadDelay :: Int -> IO ()killThread :: ThreadId -> IO ()throwTo :: Exception e => ThreadId -> e -> IO ()

15 / 27

Channels Between Threads

-- inside Control.Concurrent.Chan

data Chan anewChan :: IO (Chan a)writeChan :: Chan a -> a -> IO ()readChan :: Chan a -> IO a -- can block

16 / 27

IO and Haskell

Only things that return an IO

can do IO, have external effects, talk tothe network, do stuff.

Therefore, in the IO monad, you can doanything an imperative language can do.

17 / 27

IO References (variables)

-- inside Data.IORefdata IORef a = ...

-- createnewIORef :: a -> IO (IORef a)

-- readreadIORef :: IORef a -> IO a

-- writewriteIORef :: IORef a -> a -> IO ()

18 / 27

Forking Threads

-- inside Control.Concurrent

forkIO :: IO () -> IO ThreadId

-- alsothreadDelay :: Int -> IO ()killThread :: ThreadId -> IO ()throwTo :: Exception e => ThreadId -> e -> IO ()

19 / 27

MVars: Mutable Concurrency Variables

-- inside Control.Concurrent.MVar

data MVar a = ...

-- creationnewMVar :: a -> IO (MVar a)newEmptyMVar :: IO (MVar a)

-- writing, can blockputMVar :: MVar a -> a -> IO ()

-- reading, can blocktakeMVar :: MVar a -> IO a

-- checkingisEmptyMVar :: MVar a -> IO Bool

20 / 27

Channels Between Threads

-- inside Control.Concurrent.Chan

data Chan a

-- creationnewChan :: IO (Chan a)

-- writingwriteChan :: Chan a -> a -> IO ()

-- reading, can blockreadChan :: Chan a -> IO a

21 / 27

% telnet www.haskell.org 80Trying 128.36.229.215...Connected to bugs.haskell.org.Escape character is ’^]’.GET / HTTP/1.1Host: localhost

HTTP/1.1 200 OK

Date: Fri, 03 Apr 2009 16:46:29 GMT

Server: Apache/2.0.46 (Red Hat)

Accept-Ranges: bytes

X-Powered-By: PHP/4.3.2

Content-language: en

ETag: W/"haskellwiki:pcache:idhash:1-0!1!0!0!1!en!2--20090328210221"

Vary: Accept-Encoding,Cookie

Expires: -1

Cache-Control: private, must-revalidate, max-age=0

Last-modified: Sat, 28 Mar 2009 21:02:21 GMT

Connection: close

Transfer-Encoding: chunked

Content-Type: text/html; charset=utf-8

6660

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" >

...

22 / 27

Sockets

listenOn :: PortID -> IO Socketdata PortID= Service String| PortNumber PortNumber| UnixSocket String

accept :: Socket -> IO (Handle, HostName, PortNumber)type HostName = Stringnewtype PortNumber = PortNum Word16

23 / 27

API for our Webserver

initServer:: Int -- The port number-> (Request -> IO Response) -- The functionality of the Sever-> IO Server -- A token for the Server

type Server = ()data Request = Request {reqMethod :: String,reqURI :: URI,reqHeaders :: [(String, String)],reqBody :: String

}data Response = Response {resCode :: Int,resHeaders :: [(String, String)],resBody :: String

}

24 / 27

API for our Webserver

initServer :: Int -> (Request -> IO Response) -> IO ServerinitServerMain processBody portNo callOut = do

sock <- listenOn (PortNumber $ fromIntegral portNo)loopIO(do (h,_nm,_port) <- accept sock

forkIO $ do ln <- hGetLine hcase words ln of[mode,uri,"HTTP/1.1"] ->case parseURIReference uri ofJust uri’ -> readHeaders h mode uri’ []_ -> hClose h

_ -> hClose hreturn ()

) ‘finally‘ sClose sockwhere

loopIO m = do mloopIO m

...

25 / 27

readHeaders h mode uri hds = doline <- hGetLine hcase span (/= ’:’) line of("\r","") -> sendRequest h mode uri hds(name,’:’:rest) ->

readHeaders h mode uri(hds ++ [(name,dropWhile Char.isSpace rest)])

_ -> hClose h -- strange format

26 / 27

sendRequest h mode uri hds = doresp <- callOut $ Request { reqMethod = mode

, reqURI = uri, reqHeaders = hds, reqBody = ""}

let body = resBody resphPutStr h $ concatMap (++"\r\n") $

("HTTP/1.1 " ++ message (resCode resp)) :("Connection: close") :("Content-Length", show (length body)) :(map (\(hdr,val) -> hdr ++ ": " ++ val) $

resHeaders resp) ++"" :[]

hPutStr h bodyhClose h

27 / 27

top related