Here are a few more exercises in Haskell: you should be able to solve them
with what you've learned in lecture and from the textbook ... but be sure to
look for useful Prelude functions to help! (See below.)
count which will tell you
how many elements of a list meet some given criterion.
For example:
Main> count palindrome ["bob", "sam", "otto", "fred", "eve"] 3 Main> count isAlpha "l33t" 2 Main> count (all isAlpha) ["bob", "sam", "l33t", "foo37"] 2
PS: if you want to actually use functions like palindrome
or isAlpha in your testing, you'll need to define them. Here's a
workable definition of pal, a weaker version of the palindrome
function we defined in class (but quicker to type in); just add this to your
file of definitions:
To get access to thepal str = str == reverse str
isAlpha function and other character-oriented
tools, make sure you define a name for your module and put an import at the
top, like this:
You would add this to the very top of your file of definitions; use a name like "Lab3" for a file named "Lab3.hs" (in general, the name of the module, like "Lab3", should be capitalized, a single word, and use only letters and numbers. The corresponding file should have the exact same name but with ".hs" at the end, as in "Lab3.hs").module Lab3 where import Char
title which will take a string as
argument and return a new string with all initial letters uppercase
and all non-initial letters lowercase:
You should leave punctuation unchanged, but you can eliminate redundant word spacing (Hint: recall the> title "now is THE time, For aLL good men." "Now Is The Time, For All Good Men."
words, head
and tail functions; try working in two stages).
longest which returns all the longest
words (as defined by the words function, see below) in its String
argument. In other words, all those words which have the maximum
length of any word in the original text. For example, we should
have:
since both of these words (biggest and longest) have 7 letters each. Hint: this one is most easily solved using a series of "sub-definitions". The easiest way to do this might be to set up a specific example text as a definition in a file, then work on it interactively, developing new pieces of the definition as you go, so that your file looks something like this:longest "the biggest words here have seven letters" ==> ["biggest", "letters"]
text = "this is some sample text" y = ... text ... f x = ... z = .... f text ...
elem function from the Prelude that allowed us to treat
lists roughly like sets: it allows us to test whether the first argument is an
element (or member) of the second argument (which must be a list).
Write a function
subset :: Eq a => [a] -> [a] -> Bool which will tell if its first list
argument is a subset of the second, i.e., if all the members of the first list are also
members of the second.
Example:
Hugs> subset "ABBA" "ABC"
True
Hugs> subset "97301 USA" ['0'..'9']
False
power :: [a] -> [[a]] which will
return a list of lists such that every list that is a sublist of the original
argument will be an element of the result list. “But what about duplication and order, which
are relevant for lists, but not for sets?” you might ask.
If there are distinct-but-equal occurrences of elements in the argument list,
it's easiest to treat them as distinct for the result. As for order, just preserve
the same order as in the original list, if possible.
One way to think of it is that each member of the result comes from the original list by striking one or more (perhaps even all) of the members of the original list: do this in every possible way and you have the result. Of course, it's easier to build the list up to get the same result than to take things out ... (see the hint implicit in the formatted example below).
Here are some examples—there's a big hint in how the first one is formatted.
Example:
Hugs> power "abc"
[ "", "c", "b", "bc",
"a", "ac", "ab", "abc"]
Hugs> power [2,2,2]
[[],[2],[2],[2,2],[2],[2,2],[2,2],[2,2,2]]
(Remember, the order of elements in your results might differ from these examples!)
Be prepared to tell the types of your functions (which you can easily get by asking WinHugs), but also to describe them. Which one(s) might work on numbers, which on text, which on both? Why? You should be able to show an example or two that illustrate these possibilities.
Just for reference, here are some explanations and examples of a few useful Prelude functions: I think we've covered them in class, but a few more examples can't hurt.
filter
A higher-order function which takes a predicate
argument (i.e., a boolean-valued function) and a list,
and which returns a list of all elements for which the
predicate is True. (More specifically, it respects order
and repetition, so in essence it "deletes" only those
elements for which the predicate returns False.)
filter :: (a -> Bool) -> [a] -> [a]
So in the application "filter p xs", we have
p :: a -> Bool a predicate and xs :: [a] a list; the
result has elements from xs in the same order, with
repetitions, but without any elements for which p
returns False.
Example:
filter even [1, 2, 3, 4, 4, 3, 2, 1]
==> [2, 4, 4, 2]
all
A higher-order predicate which tests if its predicate
argument (i.e., a boolean-valued function) is true of all
the elements in a list.
all :: (a -> Bool) -> [a] -> Bool
So in the application "all p xs", we have p :: a -> Bool
a predicate and xs :: [a] a list; the result tells if
all the elements of xs return True for p.
Example:
all even [2,4..8]
==> all even [2, 4, 6, 8]
==> True
isAlpha
A predicate which tells of a character whether or not it
is an alphabetic character (i.e., whether or not it is a
letter).
isAlpha :: Char -> Bool
Example:
map isAlpha "x #"
==> [isAlpha 'x', isAlpha ' ', isAlpha '#']
==> [True, False, False]
isLower
A predicate which tells of a character whether or not it
is a lowercase alphabetic letter.
isLower :: Char -> Bool
Example:
map isLower "aA@"
==> [isAlpha 'a', isAlpha 'A', isAlpha '@']
==> [True, False, False]
-------------------
zip
A function which pairs up the elements of two lists into
a list of pairs. (Think of a zipper being pulled closed.)
If one of the lists is too short, then its elements are
"cut off" in the result.
zip :: [a] -> [b] -> [(a,b)]
Example:
zip [1..5] "abc"
==> [(1,'a'), (2,'b'), (3,'c')]
words
A function which breaks a String up into a list of
Strings ("words" from the original argument) by
breaking at (and dropping) runs of whitespace.
words :: String -> [String]
Example:
words "This is a test"
==> ["This", "is", "a", "test"]
map
A function which applies its function argument (say f)
to every element of its list argument in order to
produce a list of results.
map :: (a -> b) -> [a] -> [b]
Example:
map isLower "aA@"
==> [isAlpha 'a', isAlpha 'A', isAlpha '@']
==> [True, False, False]
maximum
A function on lists of numbers which returns the
maximum element of the list.
maximum :: Ord a => [a] -> a
{don't worry too much about that Ord business; it means
roughly that the elements of the list are, in Java's
terms, Comparable}
Example:
maximum (words "We who are about to fry salute you")
==> maximum ["We","who","are","about","to","fry","salute","you"]
==> "you"
{exercise: what ordering is being used here?}
takeWhile, dropWhile
Two functions which take or drop items from the front of a list, but
only while a given predicate is True. In other words,
this function takes one predicate argument and one
list argument, and returns either a prefix or suffix of the list such
that every element in the prefix meets the test of
the predicate (for takeWhile) or a suffix whiose first element specifically
fails the test.
takeWhile :: (a -> Bool) -> [a] -> [a]
dropWhile :: (a -> Bool) -> [a] -> [a]
Example:
takeWhile (<5) [1..]
==> [1,2,3,4]
dropWhile (<5) [1..10]
==> [5,6,7,8,9,10]