Recursion and Induction: Lexical Issues; Recursive Programming Greg - - PowerPoint PPT Presentation
Recursion and Induction: Lexical Issues; Recursive Programming Greg - - PowerPoint PPT Presentation
Recursion and Induction: Lexical Issues; Recursive Programming Greg Plaxton Theory in Programming Practice, Spring 2004 Department of Computer Science University of Texas at Austin Lexical Issues Program layout Function parameters and
Lexical Issues
- Program layout
- Function parameters and binding
- The where clause
- Pattern matching
Theory in Programming Practice, Plaxton, Spring 2004
Program Layout
- Unlike many programming languages, white space is significant in
Haskell
- Line indentation is used to delineate the scope of definitions
– A definition with initial indentation k is implicitly ended before the first subsequent line with indentation at most k
- For example, the following three lines represent a single definition
chCase c
- - change case
| upper c = uplow c | otherwise = lowup c
Theory in Programming Practice, Plaxton, Spring 2004
Program Layout: Example
- The following (unorthodox) indentation leads to the same definition for
the chCase function chCase c
- - change case
| upper c = uplow c | otherwise = lowup c
- The following indentation leads to an error, since the last line is not
considered part of the definition of chCase chCase c
- - change case
| upper c = uplow c | otherwise = lowup c
Theory in Programming Practice, Plaxton, Spring 2004
Function Parameters and Binding
- Consider the following expression, where f is a function of one argument
f 1+1
- In normal mathematics, this will be an invalid expression, and if forced,
you will interpret it as f(1+1)
- In Haskell, this is a valid expression and it stands for (f 1)+1
Theory in Programming Practice, Plaxton, Spring 2004
Function Parameters and Binding
- To apply a function to a sequence of arguments, simply write the
function name followed by its arguments; no parentheses are needed unless the arguments are themselves expressions
- Some examples involving a function g of two arguments
– The expression g x y z stands for (g x y) z – If you write g f x y, it will be interpreted as (g f x) y, so, if you have in mind the expression g(f(x),y), write it as g (f x) y – You can’t write g(f(x),y), because (f(x),y) will be interpreted as a pair, which is a single item
Theory in Programming Practice, Plaxton, Spring 2004
Function Parameters and Binding
- Note that unary minus often requires parentheses
- For example, the following expression results in an error
inc -2
- It is interpreted as (inc -) 2, which yields a type error
Theory in Programming Practice, Plaxton, Spring 2004
The where Clause
- The following function has three arguments, x, y and z, and it
determines if x2 + y2 = z2 pythagoras x y z = (x*x) + (y*y) == (z*z)
- The definition would be simpler to read in the following form
pythagoras x y z = sqx + sqy == sqz where sqx = x*x sqy = y*y sqz = z*z
Theory in Programming Practice, Plaxton, Spring 2004
The where Clause
- The following alternative also works
pythagoras x y z = sq x + sq y == sq z where sq p = p*p
Theory in Programming Practice, Plaxton, Spring 2004
Pattern Matching
- Previously we defined function imply as follows
imply p q = not p || q
- We can instead use pattern matching to define it as
imply False q = True imply True q = q
Theory in Programming Practice, Plaxton, Spring 2004
Pattern Matching
- We can also define the function imply as follows
imply False False = True imply False True = True imply True False = False imply True True = True
- Pattern matching can also involve certain sufficiently simple arithmetic
expressions suc 0 = 1 suc (n+1) = (suc n)+1
Theory in Programming Practice, Plaxton, Spring 2004
Pattern Matching
- Unfortunately, a definition such as the following is not permitted since
multiplication is not allowed with the pattern count 2*t = count t count 2*t + 1 = (count t) + 1
Theory in Programming Practice, Plaxton, Spring 2004
Recursive Programming
- Computing powers of 2
- Counting the 1s in a binary expansion
- Multiplication via addition
- Fibonacci numbers
- Greatest common divisor
Theory in Programming Practice, Plaxton, Spring 2004
Computing Powers of 2
- Here is the definition of a recursive function that computes nonnegative
integer powers of two power2 0 = 1 power2 (n+1) = 2 * (power2 n)
- What is the running time of power2?
Theory in Programming Practice, Plaxton, Spring 2004
Counting the 1s in a Binary Expansion
- Here is the definition of a recursive function that computes the number
- f 1’s in the binary representation of its argument, where we assume
that the argument is a natural number count 0 = 0 count n | even n = count (n ‘div‘ 2) | odd n = count (n ‘div‘ 2) + 1
Theory in Programming Practice, Plaxton, Spring 2004
Multiplication via Addition
- Here is a simple recursive algorithm for performing multiplication via
addition mlt x 0 = 0 mlt x (y+1) = (mlt x y) + x
- For what integer arguments does the above approach work?
- What is the running time of mlt?
Theory in Programming Practice, Plaxton, Spring 2004
Multiplication via Addition: A Faster Approach
- Consider the more general problem of computing x*y + z over three
given arguments x, y, and z
- The recursive function quickMlt, defined below, performs this task
using only addition quickMlt x 0 z = z quickMlt x y z | even y = quickMlt (2 * x ) (y ‘div‘ 2) z | odd y = quickMlt (2 * x ) (y ‘div‘ 2) (x + z)
- For what integer arguments does the above approach work?
- What is the running time of quickMlt?
Theory in Programming Practice, Plaxton, Spring 2004
Fibonacci Numbers
- Here is a recursive algorithm for computing the Fibonacci numbers
fib 0 = 0 fib 1 = 1 fib (n + 2) = (fib n) + (fib (n+1))
- What is the running time of fib?
- We will see a faster algorithm in a later lecture
Theory in Programming Practice, Plaxton, Spring 2004
Greatest Common Divisor
- The greatest common divisor (gcd) of two positive integers is the
largest positive integer that divides them both
- Here is a recursive function corresponding to (the simple version of)
Euclid’s gcd algorithm gcd m n | m == n = m | m > n = gcd (m - n) n | n > m = gcd m (n - m)
Theory in Programming Practice, Plaxton, Spring 2004
Greatest Common Divisor: Efficient Version
- Here is a more efficient version of Euclid’s gcd algorithm
egcd m n | m == 0 = n | n == 0 = m | m == n = m | m > n = egcd (m ‘rem‘ n) n | n > m = egcd m (n ‘rem‘ m)
- The running time of this algorithm is bounded by the number of bits
in the input – An exponential improvement over the simple version in terms of worst-case running time
Theory in Programming Practice, Plaxton, Spring 2004
Greatest Common Divisor: Binary Version
- Here is a an efficient “binary version” of the gcd algorithm that requires
- nly addition and bit shift operations
– Note that ‘div‘ can be implemented using a right shift bgcd m n | m == n = m | (even m) && (even n) = 2 * (bgcd s t) | (even m) && (odd n) = bgcd s n | (odd m) && (even n) = bgcd m t | m > n = bgcd (m-n) n | n > m = bgcd m (n-m) where s = m ‘div‘ 2 t = n ‘div‘ 2
- The running time of this algorithm is bounded by the number of bits
in the input
Theory in Programming Practice, Plaxton, Spring 2004