Title: Lecture 4, Oct 6, 2004
1Lecture 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
- Todays Topics
- Home work solutions to assignment 1
- Program Manipulation
- Comparing the functional paradigm
- Actions and Haskell
- Monads
- Simple Graphics
2Home work solutions
- First Recursively
- Second by combining functions
- Write a function strlen which returns the length
of a string. e.g. - strlen "abc" --gt 3
- strlen "" --gt 0
- strlen String -gt Int
- strlen 0
- strlen (xxs) 1 strlen xs
- strlenA length
- strlenB sum . map (const 1)
- strlenC foldr () 0 . map (const 1)
3Factorial
- Write a function which computes n factorial. E.g.
- fact 0 --gt 1
- fact 3 --gt 6
- fact 5 --gt 120
- factA 0 1
- factA n n (factA (n-1))
- factB n product 1..n
4ncopies
- Write the ncopies function. For example
- ncopies 3 5 --gt 5,5,5
- ncopies 4 "a" --gt "a","a","a","a"
- ncopies 0 True --gt
- ncopiesA Num a gt a -gt b -gt 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 lt- 1..n
- ncopiesD n x take n (repeat x)
5Power
- Write the power function for integers. For
example - power 5 2 --gt 25
- power 3 3 --gt 27
- power 2 5 --gt 32
- powerA x 0 1
- powerA x 1 x
- powerA x n x (powerA x (n-1))
- powerB x n product (ncopies n x)
6String to Integer
- 7) Write a function which converts a string of
digits into an Int. You will need the following
predefined function - ord 1 --gt 49
- Char to its ascii code
- follow the following "pipeline" analysis when
defining your function - "167" --gt '1','6','7' --gt 49,54,55 --gt
1,6,7 --gt (1,100),(6,10),(7,1) - --gt 100, 60, 7 --gt 167
- (hint the first function in the pipeline is
very simple. why?)
7String to Int (cont)
- Then str2int is an easy composition
- str2int String -gt Int
- str2int
- sum .
- map (uncurry ()) .
- explist .
- map (\ z -gt z -(ord '0')) .
- map ord
- The Key is the function explist
- explist 5,3,4 --gt (5,100),(3,10),(4,1)
- How many lists are traversed?
8Key Function Explist
- Useful intermediates
- reverse 1,10,100
- 1,10,100 --gt 100,10,1
- zip 3,4 100, 10, 1
- --gt (3,100), (4,10)
- Definition
- explist zs
- zip zs power 10 x x lt- reverse 0 .. n-1
- where n length zs
9Another 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)
10Program Manipulation
- Substitution of equals for equals.
- if
- name f x e
- is a definition or a theorem, then we can replace
(f n) with en/x wherever (f n) occurs. - name is the name of the definition or theorem
for reference in the proof. - en/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
11Proof
- 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
12Side 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.
13Comparative 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.
14Example Functional Code
- leftmost a -gt Bintree a -gt Bintree a
- leftmost new (Lf x) Lf new
- leftmost new (x /\ y) (leftmost new x) /\ y
- Consider
- replace Eq a gt a -gt a -gt Bintree a -gt Bintree
a - replace new old (Lf x)
- if xold 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?
15Less Resource Hungry?
- replace' Eq a gt a -gt a -gt Bintree a -gt
Bintree a - replace' new old w
- let replace2 (Lf x)
- if xold then (Lf new,True) else (Lf
x,False) - replace2 (x /\ y)
- (case (replace2 x,replace2 y) of
- ((a,False),(b,False)) -gt (x /\ y,
False) - ((a,True),(b,False)) -gt (a /\ y,True)
- ((a,False),(b,True)) -gt (x /\ b,True)
- ((a,True),(b,True)) -gt (a /\
b,True)) - in fst(replace2 w)
16Questions 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?
17Actions
- 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
18Sample 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
19A 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.
20A 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 lt- location x -- the first action
- write var (b1) -- the next
action -
21Do syntactic sugar
- do a b do _ lt- a b
- do x lt- a
- do y lt- b
- do z lt- c
- d do x lt- a y lt- b
- z lt- c d
- do x lt- a
- y lt- b
- z lt- c
- d -- uses indentation
- -- rather than
22Do syntax, types, and order
Int
IO Int
actions without v lt- ... must have type IO
()
- do x lt- f 5
- y lt- g 7
- putChar y
- return (x 4)
-
last action must must have type Io a which is
the type of do cannot have v lt- ...
semi colons separate actions, good style to
line up with opening and closing
23Monads have Axioms
- Order matters (and is maintained by Do)
- do x lt- do y lt- b c
- d
- do y lt- b x lt- c d
- Return introduces no effects
- do x lt- Return a e ea/x
- do x lt- e Return x e
24Example 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.
25the 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 lt- x
- ... -- the next action
- ... -- the action following
-
- Note that actions following aVal lt- x can
mention the variable aVal
26the return function
- The return function 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 lt- .... -- do an action which
- -- returns an int
- return (x 4) -- follow it by a no-op
- -- which does nothing
- -- and returns x4
27IO 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 -gt IO()
- ? t getLine -- get a whole line from stdin
- getLine IO String
- ? t readFile -- read a file into a String
- readFile FilePath -gt IO String
- ? t writeFile -- write a String to a file
- writeFile FilePath -gt String -gt IO ()
28A simple IO function
- ex2 IO ()
- ex2
- do c1 lt- getChar
- c2 lt- 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
- ?
29How 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.
30Example Combining IO actions
- getLine IO Char
- getLine'
- do c lt- getChar -- get a char
- if c '\n' -- if its
newline - then return "" -- no-op action
which - -- returns empty
string - -- recursively
- else do l lt- getLine' -- get a line
- return (cl) -- no-op
action - -- to cons c
to l -
- Potentially reads a string from stdin, if it is
ever performed
31Observations
- Actions are first class.
- They can be abstracted (params 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.
32Haskell 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.
33Implementation
- wc (cc,w,lc) (cc,w,lc)
- wc (cc,w,lc) (' ' xs) wc (cc1,w1,lc) xs
- wc (cc,w,lc) ('\t' xs) wc (cc1,w1,lc) xs
- wc (cc,w,lc) ('\n' xs) wc (cc1,w1,lc1) xs
- wc (cc,w,lc) (x xs) wc (cc1,w,lc) xs
- ex7
- do name lt- getLine
- z lt- 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")
-
34Example run
- Hugs session for
- C\HUGS32\lib\Prelude.hs
- C\HUGS32\lib\hugs\IORef.hs
- lect10.hs
- Maingt ex7
- lect10.hs
- lect10.hs
- The file lect10.hs has
- 2970 characters
- 1249 words
- 141 lines
- Maingt
35Interacting 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.
36Hello World with Graphics Lib
This imports a library, SOEGraphics, it contains
many functions
import SOEGraphics main0 runGraphics( do
w lt- openWindow "First window" (300,300)
drawInWindow w (text (100,200) "hello world")
k lt- getKey w closeWindow w
)
37Graphics Operators
- openWindow String -gt Point -gt IO Window
- opens a titled window of a particular size
- drawInWindow Window -gt Draw () -gt IO ()
- Takes a window and a Draw object and draws it
- Note the return type of IO()
- getKey Window -gt IO Char
- Waits until any key is pressed and then returns
that character - closeWindow Window -gt IO ()
- closes the window
- try it out
38An Action to Wait for a Space
- spaceClose Window -gt IO ()
- spaceClose w
- do k lt- getKey w
- if k ' ' then closeWindow w
- else spaceClose w
-
-
- main1
- runGraphics(
- do w lt- openWindow "Second Program"
(300,300) - drawInWindow w (text (100,200) "hello
Again") - spaceClose w
- )