next up previous
Next: About this document Up: My Home Page

More List Processing Functions

Recursion often yields simple and natural definitions of functions on lists.

The following function computes the length of its argument list by distinguishing between the empty list (the basis case) and non-empty lists (the general case).

- fun length(L) =
= if (L=nil) then 0
= else 1+length(tl(L));
val length = fn : ''a list -> int
- length[1,2,3];
val it = 3 : int
- length[[5],[4],[3],[2,1]];
val it = 4 : int
- length[];
val it = 0 : int

The next function has a similar recursive structure. It doubles all the elements in its argument list (of integers).

- fun doubleall(L) =
= if L=[] then []
= else (2*hd(L))::doubleall(tl(L));
val doubleall = fn : int list -> int list
- doubleall[1,3,5,7];
val it = [2,6,10,14] : int list

The Reverse of a List

Concatenation of lists, for which we gave a recursive definition in the last lecture, is actually a built-in operator in ML, denoted by the symbol @.

We use this operator in the following recursive definition of a function that produces the reverse of a list.

- fun reverse(L) =
= if L = nil then nil
= else reverse(tl(L)) @ [hd(L)];
val reverse = fn : ''a list -> ''a list
- reverse [1,2,3];
val it = [3,2,1] : int list
- reverse nil;
val it = [] : ''a list

Pattern Matching

We have informally used pattern matching in different context, e.g., when applying inference rules or logical equivalences.

Informally, a pattern is an expression containing variables, for which other expressions may be substituted. The problem of matching a pattern against a given expression consists of finding a suitable substitution that makes the pattern identical to the desired expression, if one exists at all.

For example, we may apply De Morgan's Law,

displaymath240

to the formula

displaymath241

to obtain an equivalent formula

displaymath242

Here the ``meta-variables'' tex2html_wrap_inline248 and tex2html_wrap_inline250 were replaced by the formulas tex2html_wrap_inline252 and q, respectively, making the left-hand side of De Morgan's law above identical to the subformula

displaymath243

of the given formula.

Function Definition by Patterns

In ML there is an alternative form of defining functions via patterns.

The general form of such definitions is:

fun <identifier>(<pattern1>) = <expression1>
| \ <identifier>(<pattern2>) = <expression2>
| \ ...
| \ <identifier>(<patternK>) = <expressionK>;
where the identifiers, which name the function, are all the same, all patterns are of the same type, and all expressions are of the same type.

For example, an alternative definition of the reverse function is:

- fun reverse(nil) = nil
= | reverse(x::xs) = reverse(xs) @ [x];
val reverse = fn : 'a list -> 'a list

In applying such a function to specific arguments, the patterns are inspected in order and the first match determines the value of the function.

- reverse nil;
val it = [] : 'a list
- reverse[3,4,5];
val it = [5,4,3] : int list

Removing Elements from Lists

The following function removes all occurrences of its first argument from its second argument list.

- fun remove(x,L) =
= if (L=[]) then []
= else (if (x=hd(L))
= then remove(x,tl(L))
= else hd(L)::remove(x,tl(L)));
val remove = fn : ''a * ''a list -> ''a list
- remove(1,[5,3,1]);
val it = [5,3] : int list
- remove(2,[4,2,4,2,4,2,2]);
val it = [4,4,4] : int list
- remove(2,nil);\ val it = [] : int list

We use it as an auxiliary function in the definition of another function that removes all duplicate occurrences of elements from its argument list.

- fun removedupl(L) =
= if (L=[]) then []
= else hd(L)::remove(hd(L),removedupl(tl(L)));
val removedupl = fn : ''a list -> ''a list
- removedupl[1,2,3];
val it = [1,2,3] : int list
- removedupl[2,2];
val it = [2] : int list
- removedupl[2,4,2,4,4,2,4,2];
val it = [2,4] : int list

Constructing Sublists

A sublist of a list L is any list obtained by deleting some (i.e., zero or more) elements from L.

For example, [], [1], [2], and [1,2] are all the sublists of [1,2].

Let us design an SML function that constructs all sublists of a given list L. The definition will be recursive, based on a case distinction as to whether L is the empty list or not.

If L is non-empty, it has a first element x. There are two kinds of sublists: those containing x, and those not containing x.

For instance, in the above example we have sublists [1] and [1,2] on the one hand, and [] and [2] on the other hand.

Note that there is a one-to-one correspondence between the two kinds of sublists, and that each sublist of the latter kind is also a sublist of tl(L).

Constructing Sublists (continued)

These observations lead to the following definition.

- fun sublists(L) =
= if (L=[]) then [nil]
= else sublists(tl(L))
= @ insertL(hd(L),sublists(tl(L)));
val sublists = fn : ''a list -> ''a list list
- sublists[];
val it = [[]] : ''a list list
- sublists[1,2];
val it = [[],[2],[1],[1,2]] : int list list
- sublists[1,2,3];
val it = [[],[3],[2],[2,3],[1],[1,3],[1,2],[1,2,3]] : int list list
- sublists[4,3,2,1];
val it = [[],[1],[2],[2,1],[3],[3,1],[3,2],
. [3,2,1],[4],[4,1],...
Here @ denotes the (built-in) concatenation operation on lists, and the function insertL inserts its first argument at the front of all elements in its second argument (which must be a list). Its definition is left as an exercise.

If we change the expression in the else-branch to

= else insertL(hd(L),sublists(tl(L)))
= @ sublists(tl(L))
all sublists will still be generated, but in a different order.

Greatest Common Divisor

The calculation of the greatest common divisor (gcd) of two non-negative integers can also be done recursively based on the following observations:

  1. gcd(n,n) = n,
  2. gcd(m,n) = gcd(n,m), and
  3. gcd(m,n) = gcd(m-n,n), if m>n.

A possible definition in ML is as follows:

- fun gcd(m,n):int = if m=n then n
= else if m>n then gcd(m-n,n)
= else gcd(m,n-m);
val gcd = fn : int * int -> int
- gcd(12,30);
val it = 6 : int
- gcd(1,20);
val it = 1 : int
- gcd(126,2357);
val it = 1 : int
- gcd(125,56345);
val it = 5 : int




next up previous
Next: About this document Up: My Home Page

Steve Skiena
Tue Aug 24 20:54:01 EDT 1999