Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

43
Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A

Transcript of Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Page 1: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Function Definition by Cases and Recursion

Lecture 2,

Programmeringsteknik del A

Page 2: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Definitions Revisited

A definition

double :: Int -> Int

double x = 2*x

•makes a true statement about the function defined,

(whatever x is, then double x and 2*x are equal)

•gives a way of computing calls of the function.

Page 3: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Quiz

Given the definition

x :: Int

x*x = 4

Is x equal to 2?

Page 4: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Quiz

Given the definition

x :: Int

x*x = 4

Is x equal to 2?

NO! This is not a valid Haskell definition.

It makes a true statement about x, but it does not

give a way of computing x.

Page 5: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Computing with Definitions

A function call is computed by •replacing the call with a copy of the right hand side, •with the argument names replaced by the actual arguments.

double :: Int -> Intdouble x = 2*x

double 8 2*8

16

Page 6: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Evaluation Order

double (3+5)

There may be more than one way to evaluate an expression:

double 8

2*(3+5)

2*8 16

You can use any order of evaluation; they all give the same result. Haskell chooses a suitable one; you don’t need to know which.

Page 7: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Sharing Evaluation

double :: Int -> Intdouble x = x+x

double (3*5)

double 15

15+15

(3*5)+(3*5)

15+(3*5)

30

Is it more work toevaluate the expression

in this order?

Page 8: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Sharing Evaluation

double :: Int -> Intdouble x = x+x

double (3*5)

double 15

15+15

(3*5)+(3*5)

30

NO!Haskell `remembers´that both occurrencesof 3*5 are really thesame, and evaluates

both in one step.

Page 9: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Definition by Cases

Often programs must make decisions, and compute different results in different cases.

Example: Define max x y to return the maximum of its

two arguments.

If x <= y, then max x y should be y.

If x>y, then max x y should be x.

Page 10: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

The Type of Booleans

We make a decision by asking: does a condition hold?

(e.g. Does x<=y hold?)

A condition is either true or false: this is a piece of data, a value!

We introduce a new basic type with two values, named after the mathematician George Boole:

True, False :: Bool

Constants begin with a capital letter.

Page 11: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Some Operators Producing Booleans

2 <= 3 True

2 > 3 False

2 < 3 True

2 == 3 False

2 /= 3 True

Note two equals signs, toavoid confusion with a

definition.

Not equals.

Page 12: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Functions Returning Booleans

Functions can return boolean results (or any other type).

Example:

inOrder :: Int -> Int -> Int -> Bool

inOrder x y z = x <= y && y <= z

a && b is True ifboth a and b are True.

Page 13: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Using Booleans to Define Functions by Cases

max :: Int -> Int -> Int

max x y | x <= y = y

max x y | x > y = x

OR

max :: Int -> Int -> Int

max x y | x <= y = y

| x > y = x

A guard: an expression oftype Bool.

If the guard is True,the equation applies.

Page 14: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Evaluation with GuardsTo evaluate a function call,

•evaluate each guard in turn until one is True,

•replace the call with a copy of the right hand side following the true guard.

max :: Int -> Int -> Intmax x y | x <= y = y | x > y = x

max 4 2 ?? 4 <= 2 False

?? 4 > 2 True

4

Page 15: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Is max Correct?

Programming is a very error prone process; programs are rarely correct `first time´.

A large part of the cost of software development goes on finding and correcting errors.

It is essential to test software: try it on a variety of inputs and see if the output is correct.

Page 16: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Choosing Test Data

Test data should be chosen carefully, to include `difficult´ cases that might induce a failure.

The max function should be tested at least with x<y, x==y, x>y, and probably combinations of positive and negative arguments.

Choose enough test examples so that every case in your program is used at least once!

Page 17: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Dijkstra on Testing

”Testing can never demonstrate the absence of errors in software, only their presence”

Edsger W. Dijkstra

(but it is very good at the latter).

Page 18: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Specifications

What do we mean by `max is correct´?

A specification formulates properties we expect max to satisfy.

Property: x <= max x y

Property: y <= max x y

Page 19: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Why Formulate Specifications?

•Helps us clarify what max is supposed to do.

•Can help in testing.

•Enables us to prove programs correct.

Page 20: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Specifications and Testing

We can define function to check whether properties hold.

prop_Max :: Int -> Int -> Bool

prop_Max x y = x <= max x y && y <= max x y

If prop_Max always returns True, then the specification is satisfied.

We can test max on many inputs without needing to inspect the results by hand.

Page 21: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Testing with QuickCheck

QuickCheck is a tool to help you test your programs.

Main> quickCheck prop_Max

OK, passed 100 tests

quickCheck generates random values to test your property thoroughly.

Page 22: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Testing with QuickCheck (2)

What if we make a mistake?

max x y | x <= y = x

| x > y = y

Main> quickCheck prop_Max

Falsifiable, after 0 tests

1

0

Page 23: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Specifications and Proofs

From the definition of max:

x <= y ==> max x y = y

x > y ==> max x y = x

Theorem: x <= max x y

Proof: Consider two cases:

Case x <= y: y = max x y, so x <= max x y.

Case x > y: max x y = x and x <= x, so x <= max x y.

Page 24: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Formal Methods

Proofs are costly and also error-prone, but can guarantee correctness.

Thorough testing is the most common method today.

Customers for safety critical software demand proofs today.

Proofs of correctness will play a growing role, thanks to

•automatic tools to help with proving,

•demand for better quality software.

Page 25: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Quiz

Define

•abs x to return the absolute value of x (e.g. abs 2 = 2, abs (-3) = 3.

•sign x to return 1 if x is positive, and -1 if x is negative.

State (and prove?) a property relating abs and sign.

Page 26: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Quiz Answer

abs x | x <= 0 = -x

| x > 0 = x

sign x | x < 0 = -1

| x > 0 = 1

| x == 0 = 0

Property: x == sign x * abs x

Did you consider this case?This can also be written

sign 0 = 0

Page 27: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Recursion

Problem: define fac :: Int -> Int

fac n = 1 * 2 * … * n

What if we already know the value of fac (n-1)?

Then fac n = 1 * 2 * … * (n-1) * n

= fac (n-1) * n

Page 28: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

A Table of Factorials

n fac n

0 1

1 1

2 2

3 6

4 24

...

Must start somewhere:we know that fac 0 = 1.

So fac 1 = 1 * 1.

So fac 2 = 1 * 2.

So fac 3 = 2 * 3.

Page 29: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

A Recursive Definition of Factorial

fac :: Int -> Int

fac 0 = 1

fac n | n > 0 = fac (n-1) * n

Base case.

Recursive case.

Page 30: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Evaluating Factorials

fac :: Int -> Int

fac 0 = 1

fac n | n > 0 = fac (n-1) * n

fac 4 ?? 4 == 0 False

?? 4 > 0 True

fac (4-1) * 4

fac 3 * 4

fac 2 * 3 * 4

fac 1 * 2 * 3 * 4

fac 0 * 1 * 2 * 3 * 4

1 * 1 * 2 * 3 * 4

24

Page 31: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

There is No Magic!

What if we define

fac :: Int -> Int

fac n = div (fac (n+1)) (n+1) ?

fac 4 div (fac 5) 5

div (div (fac 6) 6) 5

div (div (div (fac 7) 7) 6) 5

...

A true statement.

Not a usefuldefinition.

Page 32: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Primitive Recursion

Define

•f n in terms of f (n-1), for n > 0.

•f 0 separately.

What if I already know the value of f (n-1)?

Can I compute f n from it?

Page 33: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Quiz

Define a function power so that

power x n == x * x * … * x

n times

(Of course, power x n == x^n, but you should define power without using ^).

Page 34: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Quiz

Define a function power so that

power x n == x * x * … * x

n times

power x 0 = 1

power x n | n > 0 = power x (n-1) * x

Don’t forget the base case!

Since this equals(x * x * … * x) * x

n-1 times

Page 35: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

General Recursion

What if I know the values of f x for all x less than n?

Can I compute f n from them?

Example

x^(2*n) == (x*x)^n

x^(2*n+1) == (x*x)^n * x

Page 36: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Power Using General Recursion

power :: Int -> Int -> Int

power x 0 = 1

power x n

| n `mod` 2 == 0 = power (x*x) (n `div` 2)

| n `mod` 2 == 1 = power (x*x) (n `div` 2) * x

Base case is still needed.

Two recursive cases.

Why might this definition of power be preferred?

Page 37: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Comparing the Versions

First Version

power 3 5

power 3 4 * 3

power 3 3 * 3 * 3

power 3 2 * 3 * 3 * 3

power 3 1 * 3 * 3 * 3 * 3

power 3 0 * 3 * 3 * 3 * 3 * 3

1 * 3 * 3 * 3 * 3 * 3

243

Second Version

power 3 5

power 9 2 * 3

power 81 1 * 3

power 81 0 * 81 * 3

1 * 81 * 3

243

6 function calls, 5 multiplications.

4 function calls,4 multiplications.

Page 38: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

A More Difficult Example

Define prime :: Int -> Bool, so that prime n is True if n is a prime number.

What if we know whether (n-1) is prime?

What if we know whether each smaller number is prime?

NO HELP!

Page 39: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Generalise the Problem!

n is prime means No k in the range 2<=k<ndivides n.

GeneralisationReplace 2 by a variable.

Define

factors m n == True if Some k in the range m<=k<ndivides n.

So prime n = not (factors 2 n)

not x is True if x is False,and vice versa.

Page 40: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Recursive Decomposition

Problem: Does any k in the range m<=k<n divide n?

What if we know whether any k in a smaller range divides n?

Some k in the range m<=k<n divides n

if m divides n,

or some k in the range m+1<=k<n divides n.

Page 41: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Recursive Solution

factors :: Int -> Int -> Bool

factors m n

| m == n = False

| m < n = divides m n || factors (m+1) n

divides :: Int -> Int -> Bool

divides m n = n `mod` m == 0

There is no k in therange n<=k<n.

x || y is True if x is True or y is True.

Page 42: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

What is Getting Smaller?

The range m<=k<n contains n-m elements. Call this the problem size.

factors m n

| m == n = False

| m < n = divides m n || factors (m+1) n

Base case: n-m == 0

Recursive case: n-(m+1) == (n-m)-1

The problem size gets smaller in each call, until it reaches zero. So recursion terminates.

Page 43: Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.

Lessons

•Recursion lets us decompose a problem into smaller subproblems of the same kind -- a powerful problem solving tool in any programming language!

•A more general problem may be easier to solve recursively than a `simpler´ one, because the recursive calls can do more.

•To ensure termination, define a `problem size´ which must be greater than zero in the recursive cases, and decreases by at least one in each recursive call.