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

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

Embed Size (px)

Citation preview

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.