Examples and Problems
Remember to let recursion do the work for
you.
Problem:
Give rules for converting a list of 0's and 1's representing
a binary numeral, least-significant digit first, to a number.
fromBinary( [0, 1, 0, 1, 0, 1] ) ==> 42
Basis:
fromBinary([ ]) => 0;
Induction rule:
fromBinary( [ LeastSignificantDigit | Digits ] ) =>
Problem:
Give rules for converting a number to a list of 0's and 1's
representing a binary numeral, least-significant digit first.
toBinary(42) ==> [0, 1, 0, 1, 0, 1]
Here the argument is not a list, so the basis won't be [ ].
Instead it will be the number 0.
First approximation:
Basis:
toBinary(0) => [0];
Induction rule:
toBinary(N) => [ | ];
In the second rule, N can be assumed to be other than 0.
Zero would be captured by the first rule.
The rules above don't quite work; they always puts a
high-order 0 at the end of the list. This is harmless, but not
really desired. To avoid this, we need to handle the argument 0
separately.
toBinary(0) => [0];
toBinary(N) => toBinary1(N);
toBinary1(0) => [];
toBinary1(N) => [ N % 2| toBinary1(N / 2) ];
Here toBinary is the interface
function and toBinary1 is the helper or auxiliary
function.
Problem:
Give rules for converting a list of 0's and 1's representing
a binary numeral, most-significant digit first, to a
number.
The pedestrian solution is just to use the previous function
fromBinary but call it on a reversed argument:
fromBinaryMSD(List) = fromBinary(reverse(List));
How can we do it without reversing the list first?
Conversion from Binary, MSD first:
A solution from scratch is tricky. We want to avoid computing
powers of 2 explicitly. We use an auxiliary which returns
a list of two arguments, a conversion in progress and a power of
2.
This is a good example of using equational guards:
from_binary_msbf(Bits) =
[Number, Power] = from_binary_msbf1(Bits),
Number;
from_binary_msbf1([]) => [0, 1];
from_binary_msbf1([Bit | Bits]) =>
[Number, Power] = from_binary_msbf1(Bits),
[Bit*Power+Number, Power*2];
from_binary_msbf1 returns the number and the next higher
power of 2
Problem:
Give rules for converting a number to a list of 0's and 1's
representing a binary numeral, most-significant digit
first.
As before, the pedestrian solution is just to use the
previous function toBinary but reverse the result:
toBinaryMSD(Number) = reverse(toBinary(Number));
How can we do it without reversing the list after?
We use the idea of an accumulator, an argument which
accumulates a step at a time the value to be ultimately returned.
The interface function handles the case of argument 0:
to_binary_msbf(0) => [0];
to_binary_msbf(N) => to_binary_msbf(N, []);
to_binary_msbf(0, Acc) => Acc;
to_binary_msbf(N, Acc) => to_binary_msbf(N/2, [N%2 | Acc]);
The accumulator in the second function builds up the ultimate
result inside-out, starting with the least-significant digit:
Problem:
Construct function pick in the programming language
of your choice.
pick(Goal, Items)
where Goal is a non-negative integer and Items
is a sequence of positive integers, yields a pair:
The first element of the result pair is the sum of
the elements in the second element, as defined next.
The second element of the pair is a set of integers in Items
which has a sum (there many be more than one) that is closest
to Goal without exceeding it, where each item can be
used at most once.
For example:
pick(4, [1, 8, 3, 5]) ==> [4, [1, 3]]
pick(10, [1, 3, 3, 5]) ==> [9, [1, 3, 5]]
pick(0, [1, 4, 3, 5]) ==> [0, []]
In the first example, 1+3 == 4 exactly. In the second, 1+8 ==
9, the closest we can come to 10 with the numbers given. In the
third case, choosing the empty list sums to 0 exactly.
What solution paradigm should be used?
pick(Goal, []) => [0, []]; // empty list can only meet goal 0
pick(Goal, [Item | Items]) =>
Item > Goal ? pick(Goal, Items) // Item too large to use
: [Sum1, Items1] = pick(Goal-Item, Items), // Try with Item
[Sum2, Items2] = pick(Goal, Items), // Try without Item
Sum1 + Item > Sum2 ? // Which is closer?
[Sum1+Item, [Item | Items1]] // Using item
: [Sum2, Items2]; // Not using item