PAL Sessions: COMP1100 focus: 3pm daily, GEOG 202 COMP1130 focus: 1pm Thursday, GEOG 202
Assessments reminder Assignment 1: out this week, stage 1 due on 31 March (census date), stage 2 due after the teaching break (10%, redeemable on final exam) Assignment 2: out week 6, due end of week 8 (12%) Assignment 3: out week 8, due end of week 12 (15%) Mid-semester lab exam on Monday 26 March (10%, redeemable on final exam) Final exam during exam period (50%)
Problem solving in Haskell Chapter 4 of Thompson
Review exercises 1. Write a function multiply that takes two integers x and y, and produces x multiplied by y 2. Write a function double that takes an integer x, and produces x doubled 3. Write a function triple that takes an integer x, and produces x tripled
Homework: solution next lecture Write a function taxrate that takes a Double salary figure, and produces a Double tax rate, according to the following table: Salary Tax Rate at least 80000 30% at least 50000 and less than 80000 20% at least 20000 and less than 50000 10% less than 20000 0%
Homework: solution next lecture Write a function taxpayable that takes a Double salary figure, and produces a Double tax amount payable, where the tax amount is calculated as a percentage of salary, using the previous table.
Designing a program 1. What is needed? 2. Can you say anything about types? 3. What do you already know? 4. Can you use another function as a model? 5. Can you reuse a function? 6. Can you break the problem into simpler parts? 7. What if you had some existing functions?
What is needed? Suppose you are asked to return the middle of three numbers: middlenumber 2 4 3 3 middlenumber 2 4 2 2? middlenumber 2 4 2 none? No right answer!
Can you say anything about types? middlenumber :: Integer -> Integer -> Integer -> Integer May need to define types for ourselves to match the problem!
What do you already know? Recall: max :: Integer -> Integer -> Integer max x y x >= y = x otherwise = y
Can you use another function as a model? Consider finding maximum of three numbers: maxthree :: Integer -> Integer -> Integer -> Integer maxthree x y z x >= y && x >= z = x y >= z = y otherwise = z
Can you reuse a function? maxthree x y z = max (max x y) z or equivalently maxthree x y z = (x `max` y) `max` z
Can you break the problem into simpler parts? Divide and Conquer: Solve small pieces of the problem and compose into an overall solution. Bottom Up: Solve the simpler problem and build on up. Top Down: Assume you have the functions you need!
What if you had some existing functions? middlenumber :: Integer -> Integer -> Integer -> Integer Model on maxthree: middlenumber x y z condition for x to be solution = x condition for x to be solution = y Suppose we have a function between to check the conditions!
Top down design middlenumber x y z between y x z = x between x y z = y otherwise = z
Solving a problem in steps: local definitions fourpics :: Picture -> Picture fourpics pic = left `beside` right where left = right =
Solving a problem in steps: local definitions fourpics :: Picture -> Picture fourpics pic = left `beside` right where left = pic `above` invertcolour pic right =
Solving a problem in steps: local definitions Define right from scratch: fourpics :: Picture -> Picture fourpics pic = left `beside` right where left = pic `above` invertcolour pic right = invertcolour (flipv pic) `above` flipv pic
Solving a problem in steps: local definitions Then add another local definition as a helper: fourpics :: Picture -> Picture fourpics pic = left `beside` right where left = pic `above` invertcolour pic right = invertcolour flipped `above` flipped flipped = flipv pic
Solving a problem in steps: local definitions Or use the definition of left in defining right: fourpics :: Picture -> Picture fourpics pic = left `beside` right where left = pic `above` invertcolour pic right = invertcolour (flipv left)
Solving a problem in steps: local definitions Or define a local function: fourpics :: Picture -> Picture fourpics pic = left `beside` right where stack p = p `above` invertcolour p left = stack pic right = stack (invertcolour (flipv pic))
Calculating with local definitions sumsquares :: Integer -> Integer -> Integer sumsquares n m = sqn + sqm where sqn = n*n sqm = m*m
Calculating with local definitions sumsquares 4 3 = sqn + sqm where sqn = 4 * 4 = 16 sqm = 3 * 3 9 = 16 + 9 = 25
Scopes: can use definitions that occur later isodd, iseven :: Int -> Bool isodd n n <= 0 = False otherwise = iseven (n-1) iseven n n < 0 = False n == 0 = True otherwise = isodd (n-1)
Scopes: where clauses limit scope maxsq x y
Scopes maxsq x y
Types for the problem domain
Defining new types: enumerated types
Defining new types: enumerated types data Move = Rock Paper Scissors deriving (Show,Eq)
Defining new types: enumerated types data Move = Rock Paper Scissors deriving (Show,Eq) beat :: Move -> Move beat Rock = Paper beat Paper = Scissors beat Scissors = Rock lose :: Move -> Move lose Rock = Scissors lose Paper = Rock lose _ = Paper
Recursion
Recursion: factorials n fact n fact n 0 1 1 1 1 fact (n-1) * n = 1*1 = 1 2 1*2 = 2 fact (n-1) * n = 1*2 = 2 3 1*2*3 = 6 fact (n-1) * n = 2*3 = 6 4 1*2*3*4 = 24 fact (n-1) * n = 6*4 = 24
Recursion and calculation fact :: Integer -> Integer fact n n==0 = 1 n>0 = fact (n-1) * n
Recursion and calculation fact 4 fact 3 * 4 (fact 2 * 3) * 4 ((fact 1 * 2) * 3) * 4 (((fact 0 * 1) * 2) * 3) * 4 (((1 * 1) * 2) * 3) * 4 ((1 * 2) * 3) * 4 (2 * 3) * 4 6 * 4 24
Recursion: undefined values fact :: Integer -> Integer fact n n==0 = 1 n>0 = fact (n-1) * n otherwise = 0
Recursion: error values fact :: Integer -> Integer fact n n==0 = 1 n>0 = fact (n-1) * n otherwise = error "fact only defined on natural numbers"
A template for primitive recursion fun n n==0 = n>0 = fun (n-1)
Powers of two power2 :: Integer -> Integer power2 n==0 = n>0 = power2 (n-1)
Powers of two power2 :: Integer -> Integer power2 n==0 = 1 n>0 = 2*power2 (n-1)
Sum of factorials sumfacts n = fact 0 + fact 1 + + fact (n-1) + fact n sumfacts :: Integer -> Integer sumfacts n n==0 = 1 n>0 = sumfacts (n-1) + fact n
Sum of arbitrary function sumfun :: (Integer -> Integer) -> Integer -> Integer sumfun f n n==0 = f 0 n>0 = sumfun f (n-1) + f n
Sum of arbitrary function sumfun fact 3 sumfun fact 2 + fact 3 sumfun fact 1 + fact 2 + fact 3 sumfun fact 0 + fact 1 + fact 2 + fact 3 10 sumfacts n = sumfun fact n
General recursion: Fibonacci numbers fib :: Integer -> Integer fib n n==0 = 0 n==1 = 1 n>1 = fib (n-2) + fib (n-1) Clear but very inefficient!
General recursion: integer division remainder, divide :: Integer -> Integer -> Integer remainder 37 10 = 7 divide 37 10 = 3 remainder 27 10 = 7 divide 27 10 = 2 remainder 17 10 = 7 divide 17 10 = 1 remainder 7 10 = 7 divide 7 10 = 0
General recursion: integer division remainder, divide :: Integer -> Integer -> Integer remainder m n m<n = m otherwise = remainder (m-n) n divide m n m<n = 0 otherwise = 1 + divide (m-n) n
General recursion: doesn t always terminate! remainder 7 0 remainder (7-0) 0 remainder 7 0 divide 4 (-4) 1 + divide (4-(-4)) (-4) 1 + divide 8 (-4)
Black box testing Devise test data according to specification: partition data into testing groups, equivalent for all values, and choose one representative from each group be careful about special cases: boundary values of groups
Black box testing: maxthree All three values different All three values the same Two items equal, the third different: two values equal to the maximum, one other one value equal to the maximum, two others 6 4 1 6 6 6 2 6 6 2 2 6 > runtesttt testsmax
Black box testing: mysterymax mysterymax :: Integer -> Integer -> Integer -> Integer mysterymax x y z x > y && x > z = x y > x && y > z = y otherwise = z > mysterymax 6 6 2 2
Black box testing: mysterymax Needed to consider all possible different orderings: all three values different; six different orderings all three values the same; one ordering two items equal, the third different; in each consider three orderings
White box testing Use form of program to help choose data: supply data for each guard; test boundary conditions for equality case with >= or > for recursive functions test the zero case, the one case, and the general case
QuickCheck with Int and Integer fact :: Int -> Int fact n n>1 = n * fact (n-1) otherwise = 1 prop_fact n = fact n > 0 > quickcheck prop_fact
Data types, tuples, and lists Chapter 5
To compare two floats (x and y) for equality, use: A. x == y B. x /= y C. y == x D. abs (x - y) < 0.00001 E. (abs x) - (abs y) > 0.00001
Tuples A fixed number of values of (possibly different) fixed types combined into a single value. e.g., associating prices to shopping items ("Salt: 1kg", 139) ("Chips", 25) type ShopItem = (String, Int) -- giving the type a name ("Salt: 1kg", 139) :: ShopItem
Lists An arbitrary number of values of the same type combined into a single value. e.g., a basket of shopping items [("Salt: 1kg", 139), ("Chips", 25), ("Gin: 1l", 1099)] :: [ (String, Int) ] type Basket = [ ShopItem ] -- giving the type a name The empty list is [] and type String = [Char]
Tuple type (t 1, t 2,, t n ) Describes tuples of values (v 1, v 2,, v n ) where v 1 :: t 1, v 2 :: t 2,, v n :: t n Generalizes pairs, triples, quadruples, quintuples, sextuples, etc.
Examples minandmax :: Integer -> Integer -> (Integer,Integer) minandmax x y x >= y = (y,x) otherwise = (x,y)
Pattern matching: functions over tuples addpair :: (Integer,Integer) -> Integer addpair (x,y) = x+y addpair (5,8) 5 + 8 13
Patterns can contain nested patterns addpair :: (Integer,Integer) -> Integer addpair (0,y) = y addpair (x,y) = x+y shift :: ((Int,Int),Int) -> (Int,(Int,Int)) shift ((x,y),z) -> (x,(y,z)) name :: ShopItem -> String price :: ShopItem -> Int name (n,p) = n price (n,p) = p
Builtin selectors on pairs (but more difficult to read) fst (x,y) = x snd (x,y) = y addpair :: (Integer,Integer) -> Integer addpair p = fst p + snd p
Remember Fibonacci numbers? fib :: Integer -> Integer fib n n==0 = 0 n==1 = 1 n>1 = fib (n-2) + fib (n-1) Clear but very inefficient!
A more efficient solution for Fibonacci 0, 1, 1, 2, 3, 5,, u, v, (u+v), Next is sum of previous two, so let s compute it that way. We want a definition of a function that computes (u,v) = (fib n, fib (n+1)). fibstep :: (Integer,Integer) -> (Integer,Integer) fibstep (u,v) = (v,u+v) Now, we have fibpair :: Integer -> (Integer,Integer) fibpair n n==0 = (0,1) otherwise = fibstep (fibpair (n-1)) and fastfib :: Integer -> Integer fastfib = fst. fibpair