Lab 5 Patterns for List Processing CIS 252 C Introduction to

Shared by:
Categories
-
Stats
views:
14
posted:
11/21/2008
language:
English
pages:
3
Document Sample

```							Lab 5: Patterns for List Processing                                                                  CIS 252 C Introduction to Computer Science

Overview. This lab gives you some practice with some common idioms for                binding of the function arguments to the pattern (x:xs)—play the role of the
list processing. These idioms—mapping, ﬁltering, and folding—are so common            generator x <- lst.
that Haskell (and most other functional programming languages) includes spe-          As another example, consider the following function (make sure you understand
cial functions that encapsulate them. We’ll cover those functions in class soon,      what it does by trying it out on some test data):
but they are not the focus of this lab.
This lab covers material discussed in §7.4 and §9.1 of Thompson.                        addPairs :: [(Int,Int)] -> [[Int]]
addPairs pairList = [[m+n] | (m,n) <- pairList]
§1. Mapping (Applying to All)
Here is a version of addPairs written using explicit recursion:
Last week’s lab focused on list comprehensions which provide a mechanism for
deﬁning new lists out of old lists. For example, the following function accepts a       addPairs [] = []
list of integers and doubles all of the elements in it:                                 addPairs ((m,n):rest) = [m+n] : addPairs rest

doubleAll :: [Int] -> [Int]                                                         Once again, notice that the recursive deﬁnition uses exactly the same transfor-
doubleAll lst = [ 2*x | x <- lst]                                                   mation as the list-comprehension version, and tacks (using the : operator) the
ﬁrst-element result onto the result of the recursive call.
This comprehension includes a generator x <- lst and a transformation 2*x.            Note: Occasionally, you may ﬁnd that you need to put parentheses around
Because the comprehension doesn’t include any tests to ﬁlter out elements, the        the transformation portion of the recursive deﬁnition, due to operator prece-
resulting list will always contain the same number of elements as the initial list.   dence. For example, a:b:list gets interpretted as a:(b:list); if you mean
Thus, for example, doubleAll [1,3,5,7,10] will return a ﬁve-element list.             (a:b):list, you must include the parentheses.
Here is a version of doubleAll written using explicit recursion:                      Finally, sometimes you’ll need to pass around an extra argument, if the func-
tion itself takes more than one argument. For example, consider the following
doubleAll [] = []                                                                   generalization of doubleAll:
doubleAll (x:xs) = 2*x : doubleAll xs
multAll :: Int -> [Int] -> [Int]
The equation for the empty list is straightforward: doubling every element of        multAll m lst = [ m*x | x <- lst]
an empty list should result in another empty list. The second equation handles
nonempty lists and is explicit about how the new list is generated: we transform The explicit-recursion version of this function must pass around the arguent m on
the head of the list using the same transformation as in the list comprehension each call:
(2*x), and we tack it on to the front of the list obtained by transforming the rest
of the list (via the recursive call). Each recursive call has the effect of generat- multAll m [] = []
ing the next element to be operated on; thus the recursive calls—along with the      multAll m (x:xs) = m*x : multAll m xs

Page 1                                                                                                                                           January 25, 2008
Lab 5: Patterns for List Processing                                                                     CIS 252 C Introduction to Computer Science

§2. Filtering (Element Selection)                                                      §3. Folding (Combining Results)
We’ve seen in list comprehensions how one can ﬁlter out some of the elements            The list-comprehension notation is useful for converting lists into new lists, but
of the original list via adding tests to the list comprehension. For example, the       it doesn’t provide a way to convert information in lists to a nonlist form. For
following function accepts a list of integers and doubles all the elements in it that   example, a list comprehension won’t help in summing the elements of a list or in
are less than 10 (it drops the rest):                                                   ﬁnding the maximum element in the list.
However, the same type of pattern we’ve seen in the explicit-recursion functions
doubleSome :: [Int] -> [Int]
above can be used in this type of situation. The basic idea is that we can operate
doubleSome lst = [ 2*x | x <- lst, x < 10]
on individual elements of a list and combine that answer with the result obtained
Here is a version of doubleSome written using explicit recursion:                       by a recursive call.
For example, consider the following function, which sums up the elements of a
doubleSome []    = []                                                                 list of integers:
doubleSome (x:xs)
| x < 10    = 2*x : doubleSome xs                                                   sumUp :: [Int] -> Int
| otherwise = doubleSome xs                                                         sumUp [] = 0
sumUp (x:xs) = x + sumUp xs
This function is similar to the recursive deﬁnition of doubleAll, except that we
don’t always tack on the element 2*x. Instead, we only tack on those elements
Note that this deﬁnition has a similar form to what we’ve seen already, except
2*x for which the test x < 10 is satisﬁed. Recursive calls still provide the mech-
that it uses the operator + to combine the results, rather than the operator :. The
anism for “marching down” the list; at each point, we look at the ﬁrst element of
other difference is that it no longer makes sense to return the empty list in the
the list to determine whether to include its transformation in the ﬁnal result.
ﬁrst equation, because sumUp needs to return an integer.
Similarly, in Lab 4 we saw the function:
You can also perform transformations on the individual elements of the list being
sampleFun :: [(Int,Int)] -> [[Int]]                                             processed. For example, the following function sums the squares of the elements
sampleFun pairList = [[m+n] | (m,n) <- pairList, n == 2*m] of a list:

Here is a version of sampleFun written using explicit recursion:                          sumSquares :: [Int] -> Int
sumSquares [] = 0
sampleFun []    = []                                                                    sumSquares (x:xs) = x*x + sumSquares xs
sampleFun ((m,n):rest)
| n == 2*m = [m+n] : sampleFun rest                                               Finally, the following function concatenates all of the elements of a list of lists,
| otherwise = sampleFun rest                                                      to form a single list:

Page 2                                                                                                                                                January 25, 2008
Lab 5: Patterns for List Processing                                                               CIS 252 C Introduction to Computer Science

cat :: [[a]] -> [a]                                                                      getShorty :: Int -> [[a]] -> [([a],Int)]
cat [] = []
cat (x:xs) = x ++ cat xs                                                               such that (getShorty n ls) returns a list of pairs, containing exactly
those elements in ls with length less than n, paired with their length. For
For example, see what the value of cat [[1,2],[3,4],[],[6,7,8]] is.                      example,
Here, the built-in append operator (++) is used to combine the results. Even
getShorty 4 [[1..5],[17],[8,100],[],[4,6,7,9]]
though cat returns a list, the number of elements in that list bears no relation to
the number of elements in the original list. Similarly, in the ﬁrst equation, the        should return [([17],1), ([8,100],2), ([],0)], while
two occurrences of [] play two different roles: it just happens to be the case that
the result of catenating 0 lists is the empty list.                                           getShorty 6 ["sammy","puncher","terry","yancey",
"zeke"]
§4. Your Problems                                          should return [("sammy",5),("terry",5),("zeke",4)].
Important note: When ﬁlling in blanks below for list comprehensions, realize          4. Deﬁne a function getShorty’ that computes the same thing as
that blanks to the right of <- may or may not require tests. For example, the blank      getShorty, but is deﬁned by ﬁlling in the blanks in:
below might be ﬁlled in with “[1..5], even x” or simply with “[1..5]”:
getShorty’ n ls = [                 |           <-           ]
[ x | x <-              ]
5. Write a recursive function
1. Use explicit recursion to write a function                                           multPairSum :: [(Int,Int)] -> Int
prependAll :: String -> [String] -> [String]
such that multPairSum lst returns the product of the sums of pairs
such that (prependAll s ss) prepends each string in ss to the string s.            in lst. For example, (multPairSum [(1,2),(50,10),(37,63)])
For example,                                                                       should return 18000, since (1 + 2) × (50 + 10) × (37 + 63) = 3 × 60 ×
100 = 18000. Question: What is the product of 0 factors? The correct
prependAll "st" ["ang", "be", "", "lo"]                                      answer is not 0...
returns ["angst","best","st","lost"].
What To Do & When To Do It
2. Deﬁne a function prependAll’ that computes the same thing as
prependAll, but is deﬁned by ﬁlling in the blanks in:        Hand in the source code for your functions, along with a transcript that demon-
strates convincingly that the code works as required.
prependAll’ s ss = [                  |         <- ]
This lab is due by noon on Monday, February 18. You should place it in the
3. Use explicit recursion to write a function                   labeled bin in CST 3-212.

Page 3                                                                                                                                         January 25, 2008

```
Related docs