Download Recursive Functions in Haskell: Factorial and List Operations and more Summaries Cybercrime, Cybersecurity and Data Privacy in PDF only on Docsity!
PROGRAMMING IN HASKELL
Chapter 6 - Recursive Functions
Introduction
As we have seen, many functions can naturally be
defined in terms of other functions.
fac :: Int ® Int fac n = product [1..n]
fac maps any integer n to the product
of the integers between 1 and n.
Recursive Functions
In Haskell, functions can also be defined in terms of
themselves. Such functions are called recursive.
fac 0 = 1 fac n = n * fac (n-1)
fac maps 0 to 1, and any other
integer to the product of itself and
the factorial of its predecessor.
For example:
fac 3 3 * fac 2
3 * (2 * fac 1)
3 * (2 * (1 * fac 0))
Why is Recursion Useful?
❚ Some functions, such as factorial, are simpler to
define in terms of other functions.
❚ As we shall see, however, many functions can
naturally be defined in terms of themselves.
❚ Properties of functions defined using recursion
can be proved using the simple but powerful
mathematical technique of induction.
Recursion on Lists
Recursion is not restricted to numbers, but can also
be used to define functions on lists.
product :: Num a Þ [a] ® a product [] = 1 product (n:ns) = n * product ns
product maps the empty list to 1,
and any non-empty list to its head
multiplied by the product of its tail.
Using the same pattern of recursion as in product
we can define the length function on lists.
length :: [a] ® Int length [] = 0 length (_:xs) = 1 + length xs
length maps the empty list to 0,
and any non-empty list to the
successor of the length of its tail.
For example:
length [1,2,3] 1 + length [2,3]
1 + (1 + length [3])
1 + (1 + (1 + length []))
For example:
reverse [1,2,3] reverse [2,3] ++ [1]
(reverse [3] ++ [2]) ++ [1]
((reverse [] ++ [3]) ++ [2]) ++ [1]
(([] ++ [3]) ++ [2]) ++ [1]
[3,2,1]
Multiple Arguments
Functions with more than one argument can also
be defined using recursion. For example:
❚ Zipping the elements of two lists:
zip :: [a] ® [b] ® [(a,b)] zip [] _ = [] zip _ [] = [] zip (x:xs) (y:ys) = (x,y) : zip xs ys
Quicksort
The quicksort algorithm for sorting a list of values
can be specified by the following two rules:
❚ The empty list is already sorted;
❚ Non-empty lists can be sorted by sorting the
tail values £ the head, sorting the tail values >
the head, and then appending the resulting
lists on either side of the head value.
Using recursion, this specification can be translated
directly into an implementation:
qsort :: Ord a Þ [a] ® [a] qsort [] = [] qsort (x:xs) = qsort smaller ++ [x] ++ qsort larger where smaller = [a | a ¬ xs, a £ x] larger = [b | b ¬ xs, b > x]
❚ This is probably the simplest implementation of
quicksort in any programming language!
Note:
Exercises
(1) Without looking at the standard prelude, define
the following library functions using recursion:
and :: [Bool] ® Bool
❚ Decide if all logical values in a list are true:
concat :: [[a]] ® [a]
❚ Concatenate a list of lists:
(!!) :: [a] ® Int ® a
❚ Select the nth element of a list:
elem :: Eq a Þ a ® [a] ® Bool
❚ Decide if a value is an element of a list:
replicate :: Int ® a ® [a]
❚ Produce a list with n identical elements: