This week we'll try out a few more simple functions on lists (look for other data structures such as binary trees next time) and a couple of exercises on recursion. See last week's lab for tips on strategy, etc.
Write a function tabulate which will take a
single function and two successive lists of
arguments and return a list of lists of results,
representing all possible combinations of the
function with arguments from the two lists (note:
the first argument should always come from the first
list and the second argument from the second list).
Hint: you can use the following function to print
out tables in a tab/return style:
It can be called as follows:
There is also a standard unzip function which takes a list of pairs
and returns a pair of lists as a result:
Your function should behave (for example) as follows:
You might be tempted to think that the two functions zip and
unzip are inverses, and in some sense they are,
but in fact the following "theorem" is not really universally true: why?
A simple "encryption" mechanism used in Usenet newsgroups is called
"rot13". It doesn't actually encrypt text (it's too easily inverted),
but rather is used to hide text from being immediately viewed. This
can be used either for delaying punch lines to a joke or as a
simple way to block potentially objectionable material (one must
overtly "decrypt" the text, thus implicitly agreeing not to be
offended).
The idea behind the "rot13" technique is simple: every alphabetic
character in the message is "rotated" 13 letters forward through
the alphabet, wrapping back around from the end to the beginning
when necessary. All non-alphabetic symbols are preserved. Note that
upper- and lower-case letters must be treated a bit differently,
since they lie in different alphabetic ranges.
You may want to make use of the following functions:
We saw in lecture yesterday a couple of definitions of the Fibonacci function;
the code in the file linked below includes the missing version using
"accumulating parameters"
(it basically "shifts" values from p and q to q and (p+q) as it is called
successively). The standard recursive definition is also there, as well as
two slight variations on the zipped list version.
Turn on timing statistics in Hugs (using the :s +s command) and
try running each of the different functions for values such as 10, 20, 30,
100 and 1000 (well, don't try the standard recursive version for larger values,
as it is too slow). Recall that when you evaluate an expression for the second
and subsequent times, you will see some benefit from reduction on the first evaluation.
Keep track of the timings in a table and see if you can develop an equation
in terms of n, which precisely describes the number of reductions which you will
see (i.e., a polynomial in n, as in O notation, but with specific constants
included).
You may think that the list versions are still a little slow, but try the
following experiment on the ys and y values defined in the files (as well as
the j and k values defined in terms of fibl'): compare the time to generate
and print the list ys and the time to compute and print y, paying special attention
to the difference betweem timings for the first and susequent evaluations.
What can you conjecture about the apparent slow speed of the list-based
versions of Fibonacci?
(Note that there are slight differences between the fibl and fibl' functions in
terms of timing: why do you think that the use of a global versus local
definition of the list matters?)
Please have answers to the above exercises ready for the lab session on
Wednesday 9 February 2005
Your answers should include:
> title "now is THE time, For aLL good men."
You should leave punctuation unchanged, but you can eliminate
redundant word spacing (Hint: recall the words, head
and tail functions; try working in two stages).
"Now Is The Time, For All Good Men."
> tabulate (*) [1..3] [10..12]
[[10, 11, 12], [20, 22, 24], [30, 33, 36]]
prTable xss = putStr (concatMap (('\n':) . concatMap (('\t':) . show)) xss)
> tabulate (*) [1..3] [1..4]
[[1, 2, 3, 4], [2, 4, 6, 8], [3, 6, 9, 12]]
> prTable $$
1 2 3 4
2 4 6 8
3 6 9 12
unzip :: [(a,b)] -> ([a],[b])
Unfortunately, the definition of this function in the Prelude is a little obscure:
see if you can write your own definition of unzip using functions you already
know (you may also want the two functions fst and snd
which "project" the first and second halves of a pair).
Prelude> unzip [('a',1),('b',2),('c',3),('d',4),('e',5)]
("abcde",[1,2,3,4,5])
For all lists xs and ys,
unzip (zip xs ys) == (xs,ys)
A medium-sized exercise
> rot 13 "This is a message; it is a test, just a test."
"Guvf vf n zrffntr; vg vf n grfg, whfg n grfg."
(so, e.g., ord 'a' is 97);
(so, e.g., chr 97 is 'a');
(so, e.g., mod 10 3 is 1;
(so, e.g., map toUpper "foobar" is "FOOBAR");
Non-coding exercise: more fun with rabbits
Fibs.hs