1 / 38

Lecture #4, Oct 6, 2004

This lecture covers the reading assignments for Chapter 3 (Simple Graphics) of the text, as well as the solutions to Homework Assignment #1. Topics include program manipulation, comparing the functional paradigm, actions and Haskell, monads, and simple graphics. The lecture also includes exercises on writing functions for string length, factorial, and power, as well as converting strings to integers.

mbridges
Download Presentation

Lecture #4, Oct 6, 2004

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. Lecture #4, Oct 6, 2004 • Reading Assignments • Begin Reading chapter 3 (Simple Graphics) of the Text • Homework Assignment 2 • exercises 2.1 and 2.2 pp. 25 of the text • exercises 2.5 pp. 33 of the text • Today’s Topics • Home work solutions to assignment #1 • Program Manipulation • Comparing the functional paradigm • Actions and Haskell • Monads • Simple Graphics

  2. Home work solutions • First Recursively • Second by combining functions • Write a function: strlen which returns the length of a string. e.g. strlen "abc" --> 3 strlen "" --> 0 strlen :: String -> Int strlen [] = 0 strlen (x:xs) = 1 + strlen xs strlenA = length strlenB = sum . map (const 1) strlenC = foldr (+) 0 . map (const 1)

  3. Factorial Write a function which computes n factorial. E.g. fact 0 --> 1 fact 3 --> 6 fact 5 --> 120 factA 0 = 1 factA n = n * (factA (n-1)) factB n = product [1..n]

  4. ncopies Write the ncopies function. For example: ncopies 3 5 --> [5,5,5] ncopies 4 "a" --> ["a","a","a","a"] ncopies 0 True --> [] ncopiesA :: Num a => a -> b -> [b] ncopiesA 0 x = [] ncopiesA n x = x : (ncopiesA (n-1) x) ncopiesB n x = map (const x) [1..n] ncopiesC n x = [ x | y <- [1..n] ] ncopiesD n x = take n (repeat x)

  5. Power Write the power function for integers. For example: power 5 2 --> 25 power 3 3 --> 27 power 2 5 --> 32 powerA x 0 = 1 powerA x 1 = x powerA x n = x * (powerA x (n-1)) powerB x n = product (ncopies n x)

  6. String to Integer 7) Write a function which converts a string of digits into an Int. You will need the following predefined function: ord ‘1’ --> 49 Char to its ascii code follow the following "pipeline" analysis when defining your function "167" --> ['1','6','7'] --> [49,54,55] --> [1,6,7] --> [(1,100),(6,10),(7,1)] --> [100, 60, 7] --> 167 (hint: the first function in the pipeline is very simple. why?)

  7. String to Int (cont) • Then str2int is an easy composition str2int :: String -> Int str2int = sum . map (uncurry (*)) . explist . map (\ z -> z -(ord '0')) . map ord • The Key is the function explist explist [5,3,4] --> [(5,100),(3,10),(4,1)] • How many lists are traversed?

  8. Key Function Explist • Useful intermediates reverse [1,10,100] [1,10,100] --> [100,10,1] zip [3,4] [100, 10, 1] --> [(3,100), (4,10)] • Definition explist zs = zip zs [ power 10 x | x <- reverse [0 .. n-1] ] where n = length zs

  9. Another explist explist = fst . foldr g ([],1) where z `g` (zs,n) = ((z,n) : zs, n * 10) • Suppose we start with [5,3,2] • Folding g leaves • 5 `g` (3 `g` (2 `g` ([],1))) • 5 `g` (3 `g` ((2,1):[],10)) • 5 `g` (3 `g` ([(2,1)],10)) • 5 `g` ((3,10):[(2,1)],100) • 5 `g` ([(3,10),(2,1)],100) • ([(5,100),(3,10),(2,1)],1000)

  10. Program Manipulation • Substitution of equals for equals. if name: f x = e is a definition or a theorem, then we can replace (f n) with e[n/x]wherever (f n) occurs. • name: is the name of the definition or theorem for reference in the proof. • e[n/x] means e with all free occurrences of x replaced by n • For example consider: comp: (f . g) x = f (g x) • Now prove that ((f . g) . h) x = (f . (g . h)) x

  11. Proof • Pick one side of the equation and transform using rule comp: above ((f . g) . h) x = by comp: (left to right) (f . g) (h x) = by comp: (left to right) f (g (h x)) = by comp: (right to left) f ((g . h) x) by comp: (right to left) (f . (g . h)) x

  12. Side Effects and Haskell • All the Haskell programs we have seen so far have no side-effects. • This means that every expression has only one value, no matter where it occurs in the program. • This is the basis for the “substitution of equals for equals” rule. • Real programs side effect the world. • How do we reconcile these two competing properties? • Separate the “pure” world, from the “actions” • In syntax • do syntax implies a possible action • Using types. • An expression with a Monadic type (IO a) has possible actions associated with its execution.

  13. Comparative Styles • Comparing imperative programming with the functional style: data Bintree a = Lf a | (Bintree a) :/\: (Bintree a) • Consider the function that updates the left most leaf of a tree. • Imperative code loops down the nodes and makes the change in place. • Functional code makes a copy old the old structure, with minimal changes. • Imperative code is less resource hungry since it doesn't allocate as much • In functional programming it is always "safe" for trees to share sub trees.

  14. Example Functional Code leftmost :: a -> Bintree a -> Bintree a leftmost new (Lf x) = Lf new leftmost new (x :/\: y) = (leftmost new x) :/\: y • Consider: replace :: Eq a => a -> a -> Bintree a -> Bintree a replace new old (Lf x) = if x==old then Lf new else Lf x replace new old (x :/\: y) = (replace new old x) :/\: (replace new old y) • This function copies the whole tree even if doesn't need to. How can we get around this?

  15. Less Resource Hungry? replace' :: Eq a => a -> a -> Bintree a -> Bintree a replace' new old w = let replace2 (Lf x) = if x==old then (Lf new,True) else (Lf x,False) replace2 (x :/\: y) = (case (replace2 x,replace2 y) of ((a,False),(b,False)) -> (x :/\: y, False) ((a,True),(b,False)) -> (a :/\: y,True) ((a,False),(b,True)) -> (x :/\: b,True) ((a,True),(b,True)) -> (a :/\: b,True)) in fst(replace2 w)

  16. Questions to answer • Does this really help? since it still constructs the tree, but then only throws it away. • Or does it? What about lazy evaluation? • But is it any more efficient? ? t1 (Lf 4 :/\: Lf 6) :/\: (Lf 8 :/\: Lf 12) (12 reductions, 83 cells) ? replace 99 7 t1 (Lf 4 :/\: Lf 6) :/\: (Lf 8 :/\: Lf 12) (22 reductions, 94 cells) ? replace' 99 7 t1 (Lf 4 :/\: Lf 6) :/\: (Lf 8 :/\: Lf 12) (27 reductions, 124 cells) • May Be there is something to destructive update. How can we add assignments without ruining all the nice properties of functional languages?

  17. Actions • It is sometimes useful for a functional program to perform some action (or have some side effect) • Update a piece of state (assignment) • do some IO • draw graphics on a display • return an exception rather than an answer • How do we model this? • We use a Monad • A Monad is a type constructor which has an implied action. • For example: IO Int is an action which performs some IO and then returns an Int

  18. Sample Effects or Actions • State • Update a piece of the store (assignment) as well as return a final value. • Exceptional cases • There may be an error instead of a final value • Non-determinism • There may be multiple possible final values • Partial Computation • There may be nothing: no final value, or anything else • Communication • There may be external influence on the computation • Perform some Input or Output, as well as a final value. • Draw graphics on a display

  19. A Monad uses types to separate Actions (with effects) from pure computations • A Monad is a type constructor which has an implied action. • For example: a computation with type (IO Int ) • is an action which might perform some IO and which then returns an Int • Computations with non-monadic types cannot have any effects. They are pure computations. The user (and the compiler) can rely on this.

  20. A monad orders effects • A Monad specifies which effects come before others. • The “do” operator provides this control over the order in which computations occur do { var <- location x-- the first action ; write var (b+1)-- the next action }

  21. Do syntactic sugar do { a; b } = do { _ <- a; b } do { x <- a ; do { y <- b ; do { z <- c ; d }}} = do {x <- a; y <- b; z <- c; d } = do x <- a y <- b z <- c d -- uses indentation -- rather than ;

  22. Do: syntax, types, and order do { x <- f 5 ; y <- g 7 ; putChar y ; return (x + 4) } Int IO Int actions without v <- ...must have type IO () last action must must have type Io a which is the type of do cannot have v <- ... semi colons separate actions, good style to line ; up with opening { and closing}

  23. Monads have Axioms • Order matters (and is maintained by Do) do { x <- do { y <- b; c } ; d } = do { y <- b; x <- c; d } • Return introduces no effects do { x <- Return a; e } = e[a/x] do { x <- e; Return x } = e

  24. Example Monads • IO a • Perform an IO action (like read or write to a file or stdin or stdout) and then return an item of type: a • GUI a • Perform a GUI action (like draw a pull-down menu) and then return an item of type: a • State t a • Perform an action which could change the value of a mutable variable (like an assignment) in a state thread t, and then return an item of type: a • Parser a • Read some input to build an item of type: a, then chop the items used to build it off the input device. Also a parse may fail so must handle failure as well.

  25. the do syntax • Let x be some action with type: Action a • I.e. Action is one of IO, GUI, State, Parser etc. • Then we can “extract” the object with type: a, and sequence this action with other actions by using the do syntax of haskell. do { aVal <- x ; ... -- the next action ; ... -- the action following } • Note that actions following aVal <- x can mention the variable aVal

  26. the return function • The returnfunction takes an object of type: a, and turns it into an action of type: Action a, which does nothing -- it “lifts” a value to an action which is a no-op do { x <- .... -- do an action which -- returns an int ; return (x + 4) -- follow it by a no-op } -- which does nothing -- and returns x+4

  27. IO actions • Each function performs an action of doing some IO ? :t getChar -- get 1 char from stdin getChar :: IO Char ? :t putChar -- put Char to stdout putChar :: Char -> IO() ? :t getLine -- get a whole line from stdin getLine :: IO String ? :t readFile -- read a file into a String readFile :: FilePath -> IO String ? :t writeFile -- write a String to a file writeFile :: FilePath -> String -> IO ()

  28. A simple IO function ex2 :: IO () ex2 = do { c1 <- getChar ; c2 <- getChar -- the newline ; putChar c1 ; putChar c2 } ? ex2 -- I type this to Hugs a -- waits for input, I type: a\n a -- putChar prints a -- putChar prints the \n ?

  29. How to perform an IO action • Some thing of type: IO Int is a potential action which will return an Int, if it is ever performed. • In order for the action to occur, it must be performed. • Any thing with type : IO a typed at top level will be performed (nothing else is ever performed). Stated another way • This is the only way that an action can be performed. • An actionful program builds up a potential action, which is finally performed when typed at top-level. • Big actionful programs can be built by combining smaller actionful programs using do. • No action is ever performed until typed at top level.

  30. Example: Combining IO actions getLine’ :: IO [Char] getLine' = do { c <- getChar -- get a char ; if c == '\n' -- if its newline then return "" -- no-op action which -- returns empty string -- recursively else do { l <- getLine' -- get a line ; return (c:l) -- no-op action } -- to cons c to l } • Potentially reads a string from stdin, if it is ever performed

  31. Observations • Actions are first class. • They can be abstracted (param’s of functions) • Stored in data structures. -- It is possible to have a list of actions, etc. • Actions can be composed. • They can be built out of smaller actions by glueing them together with do and return • They are sequenced with do much like one uses semi-colon in languages like Pascal and C. • Actions can be performed (run). • separation of construction from performance is key to their versatility. • Actions of type: Action () are like statements in imperative languages. • They are used only for their side effects.

  32. Haskell separates Actions from Pure computation • The unix wc (word count) program, reads a file and then prints out counts of characters, words, and lines. • Reading the file is an actionfull computation, but computing the information is a pure computation. • strategy • Write a function that counts the number of characters, words, and lines in a string. • Purely functional • number of lines = number of ‘\n’ • number of words ~= number of ‘ ’ plus number of ‘\t’ • Write an actionfull program that reads a file into a string and which prints out the result • combine the two.

  33. Implementation wc (cc,w,lc) [] = (cc,w,lc) wc (cc,w,lc) (' ' : xs) = wc (cc+1,w+1,lc) xs wc (cc,w,lc) ('\t' : xs) = wc (cc+1,w+1,lc) xs wc (cc,w,lc) ('\n' : xs) = wc (cc+1,w+1,lc+1) xs wc (cc,w,lc) (x : xs) = wc (cc+1,w,lc) xs ex7 = do { name <- getLine ; z <- readFile name ; let (cc,w,lc) = wc (0,0,0) z ; putStr ("The file: "++ name ++ " has \n "++(show cc)++ " characters\n "++(show w)++ " words\n "++(show lc)++ " lines\n") }

  34. Example run Hugs session for: C:\HUGS32\lib\Prelude.hs C:\HUGS32\lib\hugs\IORef.hs lect10.hs Main> ex7 lect10.hs lect10.hs The file: lect10.hs has 2970 characters 1249 words 141 lines Main>

  35. Interacting with the world through graphics • Our first example of an action is found in chapter 3 • The action is to pop up a window and to draw pictures in the window.

  36. Hello World with Graphics Lib This imports a library, SOEGraphics, it contains many functions import SOEGraphics main0 = runGraphics( do { w <- openWindow "First window" (300,300) ; drawInWindow w (text (100,200) "hello world") ; k <- getKey w ; closeWindow w } )

  37. Graphics Operators • openWindow :: String -> Point -> IO Window • opens a titled window of a particular size • drawInWindow :: Window -> Draw () -> IO () • Takes a window and a Draw object and draws it • Note the return type of IO() • getKey :: Window -> IO Char • Waits until any key is pressed and then returns that character • closeWindow :: Window -> IO () • closes the window • try it out

  38. An Action to Wait for a Space spaceClose :: Window -> IO () spaceClose w = do { k <- getKey w ; if k == ' ' then closeWindow w else spaceClose w } main1 = runGraphics( do { w <- openWindow "Second Program" (300,300) ; drawInWindow w (text (100,200) "hello Again") ; spaceClose w } )

More Related