eecs 700 functional programming - ittc.ku.eduandygill/teaching/2010/eecs700/slides12.pdf ·...
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