Вы находитесь на странице: 1из 5

Haskell Programming

Practice Driving Test

Human Coding

The maximum total is 25. Credit will be awarded throughout for the style, clarity and the appropriate use of list comprehensions, higher-order functions etc. It is important that you comment out any code that does not compile before you complete the test. There will be a THREE mark penalty applied to any program that does not compile.

Human Coding
The standard ASCII code uses 7 bits to encode each character, so a string with 6 characters requires a minimum of 42 bits. Human coding uses variable length codes in order to reduce the number of bits required to represent a string. The code is dened by a binary tree with characters at its leaves, called the Human Coding Tree. The code for a particular character, c say, is a path through the tree from the root to the leaf containing c. For example, using the following Human coding tree:

k
the string attack would be coded as: RRLLRRRLRRLL

where L and R respectively mean go left and go right through the tree; this is equivalent to a 12-bit representation (110011101100 in this case) cf 42 bits for standard ASCII. A Human tree is generated from a given source list and is designed so that the most frequently occurring elements in the list appear near the top of the tree - we want the paths to these leaves to be as short as possible. We could represent a Human tree as a simple algebraic data type with the source symbols (only) appearing at the leaves of the trees. However, to simplify this exercise, were going to add frequency counts to each node and leaf: Each leaf (Tip) will store both an element from the source list and a count of the number of times that element appeared in the source list. Each internal node (Node) will store, in addition to its two subtrees, the sum of the frequency counts of all the Tips in those subtrees. In this sense the tree is well formed; all Human trees in this exercise can be assumed to be well formed. As an example, the tree above was created using the source string aatatttactaccattatktk (9 ts, 7 as, 3cs and 2 ks); if we add the frequency counts to the tree we get the tree shown below. Human trees with these added counts can be represented in Haskell as follows: data Huffman a = Tip Int a | Node Int ( Huffman a ) ( Huffman a ) deriving (Show) One tree of type Huffman is dened to be equal to another i their frequency counts are the same. Similarly, one tree is dened to be smaller than another i its frequency count is smaller. In order to implement this, the type Huffman has been made an instance of the Eq and Ord classes in the template le so that the operators ==, /=, <, <=, >, >=, max and min are all dened appropriately on Huffmans. Thus, for example, 2

21

t 9

12

a 7

k 2

c 3

Main> (Tip 3 c) <= Tip 1 d False Main> max (Tip 4 a) (Node 12 (Tip 8 x) (Tip 4 y)) Node 12 (Tip 8 x) (Tip 4 y) You will need to exploit this ordering later on. A function fcount :: Huffman a -> Int that returns the frequency count associate with a given tree, has also been dened in the template: fcount ( Tip n x ) = n fcount ( Node n t1 t2 ) = n In this exercise you are going to use these types and functions to build the Human tree for a given source list.

What to do
1. Dene a function insert :: Ord a => a -> [ a ] -> [ a ] that will insert an item into an ordered list of items (ascending order), returning a new ordered list. For example, insert 5 [4,6,9] should yield [4,5,6,9]. Do not attempt to use the built-in insert function (in module List dene your own version). (3 marks) 2. Dene a function count :: Eq a => a -> [ a ] -> ( a, Int ) that given an item and a list of items of the same type will return a pair comprising the item and a count of the number of times that item occurs in a given list. For example, count n "announce" should return (n,3). (3 marks) 3. Using count, dene a function countAll :: Eq a => [ a ] -> [ a ] -> [ ( a, Int ) ] that given two lists, s1 and s2, will compute the number of times each element of the second list occurs in the rst. The result should be a list of pairs, each of the form (x,n), where x is an element (of s2) and n is the number of times x occurs in s1. For example countAll "attack" "atck" should return [(a,2),(t,2),(c,1),(k,1)]. (3 marks)

4. Using countAll dene a function table :: Eq a => [ a ] -> [ ( a, Int ) ] that given a list s will return for each unique element of s a pair (e,n), where e is the element and n is the number of times e occurs in s. For example, table "attack" should return [(a,2),(t,2),(c,1),(k,1)] (in some order) as before. Notice that you will need to remove duplicate list entries at some point. To do this, use the nub function from the List module. Note that the List module is already imported in the template le. (3 marks)

Building a Human Tree


Youre now going to build a Human tree from a given source list. To do this you start by using table to build a count of the number of times each element occurs in s. Now, for each element (x,n) of the result, build the Human tree Tip n x. You now have a list of Human trees, all of which are tips. Now use the predened sort function from the module List to sort the trees in ascending order of their frequency counts. Note that sort will do the right thing here because of the dened ordering on Human trees in terms of the frequency counts (see above). As an example, given the string "aatatttactaccattatktk" (this string is predened and called testString in the template le), the table function rst generates [(a,7),(t,9),(c,3),(k,2)]. After turning each element into a tip and sorting the list of tips you get: [Tip 2 k,Tip 3 c,Tip 7 a,Tip 9 t]. Now you do the following to the above list of trees: take the two smallest (i.e. leftmost) trees in the list, merge them to form a bigger tree, and then use the given insert function to insert the merged tree into the remaining elements of the list, preserving the frequency count order. Now repeat the process until the list has just a single (big) tree in it - this tree is the required result. To merge two trees t1 and t2 with frequency counts n1 and n2 respectively you simply build a new node (Node) whose frequency count is n1+n2, whose left subtree is the smaller of t1 and t2 (i.e. t1 by virtue of the fact that the original list is ordered) and whose right subtree is the larger of t1 and t2 (i.e. t2). Note that its a simple non-recursive function. As an example, starting with [Tip 2 k,Tip 3 c,Tip 7 a,Tip 9 t] we rst combine the two leftmost trees giving Node 5 (Tip 2 k) (Tip 3 c) We then insert this tree into the remainder of the original list giving the new list [Node 5 (Tip 2 k) (Tip 3 c),Tip 7 a ,Tip 9 t]. Doing this again we get [Tip 9 t,Node 12 (Node 5 (Tip 2 k) (Tip 3 c)) (Tip 7 a)] Doing this one more time we arrive at the singleton list [Node 21 (Tip 9 t) (Node 12 (Node 5 (Tip 2 k) (Tip 3 c)) (Tip 7 a))] which is the representation of the tree shown above. Thus... 5. Dene a function merge :: Huffman a -> Huffman a -> Huffman a that will merge two Human trees in the manner described above. (2 marks) 6. Dene a function reduce :: Ord a => [ Huffman a ] -> Huffman a that given a nonempty list of Human trees will return a single tree by repeated application of merge and insert as described above. Hint: You can use pattern matching to pick o the rst two elements of a given list thus: reduce ( t1 : t2 : ts ) = ...

The base case is of the form reduce [ t ] = .... A precondition is that the argument list in non-empty. (4 marks) 7. Dene a function buildTree :: ( Eq a, Ord a ) => [ a ] -> Huffman a that will combine table, sort and reduce to generate the Human tree corresponding to the given nonempty list. For example buildTree "aatatttactaccattatktk" (dened in the template as testString) should generate the above tree. (4 marks) 8. Note: the following two functions carry only THREE marks in total so you should only spend time on them when youve completed the above questions. Dene two functions: encode, which takes a string and a Human tree and produces the code for the string, and decode, which takes a Human tree and the code of a string and returns the decoded string. The constructors L and R are dened in the template le in the data type Step. Note also the type synonym type Path = [Step] For example: Main> encode "attack" t1 [R,R,L,L,R,R,R,L,R,R,L,L] Main> decode t1 (encode "attack" t1) "attack" (3 marks)

Вам также может понравиться