4.9 More Recursion Examples

Answers to Exercises, by Jared Jackson

Problem 1

• Give a set of rules for a function which computes the list of squares of each of a list of numbers. (This could be done with map, but do it from scratch instead.)

rex> squares([]) => [];

rex> squares([A|L]) => [A*A | squares(L)];

Problem 2

• • Give a set of rules for computing the sum of a list of numbers; for computing the product of a list of numbers. (This could be done with reduce, but do it from scratch instead.)

Sum

rex> sum(L) = sum(L,0);

rex> sum([],N) => N;

rex> sum([A|L],N) => sum(L,N+A);

Product

rex> product(L) = product(L,1);

rex> product([],N) => N;

rex> product([A|L],N) => product(L,N*A);

Problem 3

• • Using your function days_of_month constructed in an earlier exercise, give rules for the function total_days which takes as an argument a list of months and returns the sum of the days in those months.

rex> total_days(L) = total_days(L,0);

rex> total_days([],N) => N;

rex> total_days([A|L],N) => total_days(L,N + month_to_days(A));

Problem 4

• • Give a set of rules for computing the average of a list of numbers (use 0 for the average of an empty list).

rex> average(L) = average(L,0,0);

rex> average([],0,0) => 0;

rex> average([],N,M) => N/M;

rex> average([A|L],N,M) => average(L,N+A,M+1);

Problem 5

• • Indicate two different ways to compute the sum of the squares of a list of numbers.

Low-Level Method

rex> sum_square(L) = sum_sq(L,0);

rex> sum_sq([],N) => N;

rex> sum_sq([A|L],N) => sum_sq(L,(A*A) + N);

High-Level Method

rex> sum_square(L) = reduce(+, 0, map((X) => X*X, L));

Problem 6

• • Give rules which define the function flip, which operates on lists, and exchanges successive pairs of elements. If there is an odd number of elements, the last element is left as is. For example:

flip([1, 2, 3, 4, 5, 6, 7]) ==> [2, 1, 4, 3, 6, 5, 7]

Suggestion: Use a rule which matches on the first two elements, rather than just one:

flip([A, B | L]) => .... ;


rex> flip([]) => [];

rex> flip([A]) => [A];

rex> flip([A,B|L]) => [B,A | flip(L)];

Problem 7

• • • Give rules for the function at_least which tells whether a list has at least a certain number of elements. For example:

at_least(3, [1, 2, 3]) ==> 1

at_least(3, [1, 2]) ==> 0

Avoid counting all of the elements of the list. This is unnecessarily inefficient for large lists.


rex> at_least(X,L) = at_least(X,L,1);

rex> at_least(X,[],C) => 0;

rex> at_least(X, [A|L] ,C) => X <= C ? 1 : at_least(X,L,C+1);

Problem 8

• • • Like the previous problem, except at_most.

rex> at_most(X,L) = at_most(X,L,1);

rex> at_most(X,[],L) => 1;

rex> at_most(X, [A|L], C) => X < C ? 0 : at_most(X,L,C+1);

Problem 9

• • The function select has the property of selecting the Ith element of a list, I >= 0, or returning a special value Other if there is no such element (the list is not long enough). That is,

select(I, [X0, X1, ...., XN-1], Other) ==> XI if I < N

select(I, [X0, X1, ...., X N-1], Other) ==> Other if I >= N

Give a set of rules for select.


rex> select(I,L,X) = select(I,L,X,0);

rex> select(I,[],X,C) => X;

rex> select(I,[A|L],X,C) => I == C ? A : select(I,L,X,C+1);

Problem 10

• • The function find_index has the property of computing the index of the first occurrence of a given element within a list. If there is no such occurrence, -1 is returned. For example,

find_index('d', ['a', 'b', 'c', 'd', 'e']) ==> 3

find_index('a', ['a', 'b', 'c', 'd', 'e'] ==> 0

find_index('g', ['a', 'b', 'c', 'd', 'e']) ==> -1

Give a complete set of rules for find_index.


rex> find_index(X,L) = find_index(X,L,0);

rex> find_index(X,[],C) => -1;

rex> find_index(X, [A|L], C)=> X == A ? C : find_index(X,L,C+1);

Problem 11

• • • Give rules for a function remove_duplicates which removes all duplicates in a list. For example

remove_duplicates([1, 2, 1, 3, 1, 2, 3]) ==> [1, 2, 3]


rex> remove_duplicates([]) => [];

rex> remove_duplicates([A|L]) => member(A,L) ? remove_duplicates(L) : [A | remove_duplicates(L);

Problem 12

• • Give rules for a function that gives the value of a list representing the 2-adic representation of a number, least-significant digit first, using the digits 1 and 2.

Problem 13

• • • Give rules for a function that gives the list representation of a number in 2-adic form, least-significant digit first.

Problem 14

• • • Give rules for a function that produces the list of prime factors of a natural number. For example:

factors(72) ==> [2, 2, 2, 3, 3]

Problem 15

• • Using functions above, give rules for a function that produces the unique prime factors of a natural number. For example

unique_factors(72) ==> [2, 3]


rex> unique_factors(X) = remove_duplicates(factors (X));

Problem 16

• • Give rules for the function subst which makes substitutions in a list. Specifically, subst(A, L, R) returns a new list which is like list L except that whenever A would have occurred as a member of L, R occurs instead.

rex> subst(A,[],R)=>[];

rex> subst(A, [Z|L], R, N)=> A == Z ? [R | subst(A,L,R)] : [Z | subst(A,L,R)];

Problem 17

• • By adding an extra argument, and assuming integer functions mod and div, generalize the function add_bin to a function which adds in an arbitrary radix.

Problem 18

• • • Devise a function which will multiply two numbers represented as a list of bits, least-significant-bit first. Notice that this function has some advantage over the standard multiplication function found in most programming languages, namely that it will work for arbitrarily-large numbers.

Problem 19

• • • Sometimes we use numeral systems of mixed radix. For example, in referring to time within a given month, we could use expressions of the form D:H:M:S for days, hours, minutes, and seconds. H ranges from 0 to 24, M from 0 to 59, and S from 0 to 59. To compute the number of seconds from the start of the day corresponding to a given time, we'd compute:

S + 60*(M + 60*(H+24*D)).

Generalize this mixed radix computation by giving rules for a function value that takes as arguments two lists, one giving the ranges and another giving the ordinal numbers within these ranges. For example, in the current case we would call

value( [S, M, H, D], [60, 60, 24] )

Problem 20

• • • Devise a function that will divide one number represented in binary by another, yielding a quotient and a remainder. This function should return the pair of two items as a list. Do the division digit-by-digit, don't convert to another form first.

Problem 21

• • The function keep takes two arguments: a predicate and a list: keep(P, L) is the list of those items in L such that P is true for the item. For example,

keep(odd, [1,3,2,4,6,7]) ==> [1,3,7]

Provide rex rule definitions for keep.

rex> keep(F,[]) => [];

rex> keep(F,[A|L]) => F(A) ? [A | keep(F,L)] : keep(F,L);

Problem 22

• • The function drop is like function keep above, except that the items for which P is not true are kept. For example,

drop(odd, [1,3,2,4,6,7]) ==> [2,4,6]

Provide rex rule definitions for drop.

rex> drop(F,[]) => [];

rex> drop(F,[A|L]) => F(A) ? drop(F,L) : [A | drop(F,L)];

Problem 23

• • The function select takes two arguments: a list of 0's and 1's and another list, usually of the same length. select(S, L) is the list of those items in L for which the corresponding element of S is 1. For example,

select([1,0,0,1,1,0], [1,3,2,4,6,7]) ==> [1,4,6]

Provide rex definitions for select.

rex> select([],M) => [];

rex> select(L,[]) => [];

rex> select([A|L], [B|M]) => A == 1 ? [B | select(L,M)] : select(L,M);

Problem 24

• • Iterated function systems are used for producing so-called "fractal" images. These entail applying a function repeatedly to an initial seed argument. Let

FN(X)

denote

F(F(F...(F(X))...))

N applications of F

including the definition:

F0(X) = X.

Give rewrite rules for the function iterate informally defined by:

iterate(N, F, X) ==> FN(X)

Problem 25

• • • Restate the definition of Ackermann's function using iterate.

Problem 26

• • • By indefinite iteration we mean iteration that stops when some condition is true, rather than by iterating a pre-determined number of times. The condition for stopping is best expressed as a predicate, say P. Give the rewrite rules for a function

indefinite_iterate(P, F, X)

defined to compute

Fn(X)

where n is the least value of N such that P(FN(X)) == 1.

Problem 27

• • • Give the rules for a function which transposes a matrix represented as a list of lists. Your function can assume that each "row" of the matrix has the same number of elements without checking. You might, however, wish to construct a separate function which checks the integrity of the matrix. Check your definition carefully and show that the types match up.

Problem 28

• • • Referring to the previous problem, if you understand matrix addition and multiplication, construct functions which carry out these operations.

Problem 29

• • • • If you understand matrix inversion, construct a function which carries out this operation.

Problem 30

• • Show how to use enumeration to define the function radix without using the % and / functions.


Return