CIS 554 Haskell 1: Exercises
Fall 2016, David Matuszek

Purposes of this assignment


How to read type declarations

In the Haskell REPL, :t thing will tell you the type of thing. Here are some examples:

Type Interpretation
not :: Bool -> Bool not is a function that, given a boolean value, returns a boolean value.
head :: [a] -> a head takes a list of some arbitrary type a, and returns a value of type a.
mod :: Integral a => a -> a -> a mod takes two values of type a, which must be an Integral type, and returns a value of type a.
map :: (a -> b) -> [a] -> [b] map takes a function from a to b, and a list of a, and returns a list of b.

Simple Haskell exercises

Write the following functions. Where built-in equivalents exist, do not define a function in terms of the equivalent built-in function. For example, don't say let member = elem. (You can use elem in other definitions, though.)

The following functions can all be defined in a single line, so try to do so. They do not need to work for infinite lists.

member :: Eq a => a -> [a] -> Bool
Returns true if the element occurs in the list.
count :: (Num a, Eq a1) => a1 -> [a1] -> a
Counts the number of times a value occurs in a list.
forall :: (a -> Bool) -> [a] -> Bool
Tests whether all elements of a list satisfy a given condition.
exists :: (a -> Bool) -> [a] -> Bool
Tests whether any element of a list satisfies a given condition.
single :: (a -> Bool) -> [a] -> Bool
Tests whether exactly one element of a list satisfies a given condition.
mostly :: (a -> Bool) -> [a] -> Bool
True if there are more elements in the list that satisfy the predicate than elements that fail to satisfy the predicate.
The following functions implement common set operations. At least some of them can be written as a single line. Except for isSet and makeSet, you may assume that the lists are "sets," that is, contain no duplicate elements.
isSet :: Eq a => [a] -> Bool
True if the list contains no duplicate elements.
makeSet :: Eq a => [a] -> [a]
Remove duplicate elements from a list.
subset :: Eq a => [a] -> [a] -> Bool
True if every element in the first set also occurs in the second set.
equalSet :: Eq a => [a] -> [a] -> Bool
True if the two sets contain the same elements (not necessarily in the same order).
setDiff :: Eq a => [a] -> [a] -> [a]
The set of values that are in the first set but not in the second set.
setUnion :: Eq a => [a] -> [a] -> [a]
The set of values that are in either or both sets.
setIntersection :: Eq a => [a] -> [a] -> [a]
The set of values that are in both sets.


Provide tests for the above functions. Haskell does not come with a testing framework, and I would rather not ask you to download and install one, so here's a very small framework for you to use.

assertTrue :: Bool -> String -> IO ()
assertTrue x claim = if x
                       then putStrLn claim
                       else putStrLn $ "*** Untrue: " ++ claim   

assertFalse :: Bool -> String -> IO ()
assertFalse x claim = assertTrue (not x) claim  

assertEqual :: (Eq a, Show a) => a -> a -> IO ()
assertEqual x y = if x == y
                    then putStrLn $ (show x) ++ " equals " ++ (show y)
                    else putStrLn $ "*** " ++ (show x) ++ " does not equal " ++ (show y)
And here is a brief example of its use:
main = do
  assertTrue (member 3 [1, 2, 3, 4]) "3 is in the list [1, 2, 3, 4]"
  assertFalse (member 7 [1, 2, 3, 4]) "7 is not in the list [1, 2, 3, 4]"
  assertEqual 3 (count 'a' "abracadabra")

A small program

Write a program to read lines from the user, translate each line read into the "-idig-" version of Gibberish, and print the result out to the user. See the article in Wikipedia for the exact rules; since division into syllables is somewhat complex, we will use a simplified version.

Our (simplified) rules for converting English to Gibberish are:

There are two other "clean up" rules:

Do not do any other cleanup. Don't worry about words that are all capitals, punctuation marks inside words, punctuation marks at the beginning of a word, etc.

If there are any ambiguities in how to translate to Gibberish, do whatever makes sense to you, make a note of your decision in comments in your test file, and make sure your tests enforce that decision.

Provide type declarations for all your functions, and unit tests for all your non-I/O functions.

The Haskell functions words and unwords may be helpful.

Due date

Your program is due to Canvas before 11:59pm Tuesday, October 25.