7. Maybe

Ordering list items. The Maybe typeclass.

The Maybe class is built into the standard prelude, so you will only need to import Data.Maybe if you want some of the more advanced functions.

Sorting from Data.List

When you sort a tuple, Haskell sorts based on the first item in the tuple, then the second item to break ties in the first, etc. You can import Data.List to get the sort function along with zillions of other functions detailed in Chapter 7.

sort [(3,4),(5,1),(3,1),(1,2)]==[(1,2),(3,1),(3,4),(5,1)]

Top List Exercises

  1. top3list :: [Int] -> [Int]: Give the three greatest integers, in decreasing order.

  2. toplist gives the n greatest items, in decreasing order.

     toplist :: (Ord a) => Int -> [a] -> [a]
    
  3. top3By gives the top 3 items organized according to the resuts from a function.

     top3By :: (Ord a) => (a -> Int) -> [a] -> [a]
    

    Example:

f x = x^2
g x = 10-3*x
h x = x

ws = [10, -20, 15, -50, 30]
check_top3By = [
                 top3By f ws == [-50,30,-20],
                 top3By g ws == [-50,-20,10],
                 top3By h ws == [30,15,10]
                 ]

Testing code

Signatures and tests.

top3list xs = xs
-- gives a list of the greatest 10 integers
-- in the input, in decreasing order
numlist = [99,30,40,100,80,5]
ce1 = [
  [100, 99, 80] == top3list numlist
  , [100,99,80,40] == toplist 4 numlist
  , [-90,80,-60]==top3By (abs) [-90,80,-60,30,40]
  , ["Jaylin","Matt","Kid"]==top3By (length) ["KJ","Kid","OK","Matt","Ji","Jaylin"]
  ]
-- 2. see above
-- 3. Hint: try sort on a tuple
top3By :: (Ord a) => (a -> Int) -> [a] -> [a]
top3By f xs = xs

Maybe

  1. Write a function that takes in a number and produces Just that number when the number is at most 80, otherwise Nothing.

  2. Write a function investigate words k that searches a list of String for a word with exactly k letters. Return Just word for the first such word that is found. Nothing if there is no such word.

     investigate :: [String] -> Int -> Maybe String
     investigate _ _ = Just "fixme"
     ex_inv_2 = ["chem","phys","orgo"]
     check_investigate = [
         Just "yes" == investigate ["no","yes","kinda"] 3
         ,Nothing == investigate ex_inv_2 5
         ,Just "chem" == investigate ex_inv_2 4
     ]
    
  3. Write a function might_add :: [Maybe Int] -> Int that adds up all of the integers in a list and ignores Nothing if it appears.

     might_add :: [Maybe Int] -> Int
     might_add _ = 0
     check_might =
         20 == might_add [Nothing, Just 7, Just 13, Nothing]
    

7. Application: Word Counter

Given a list of words (strings), produce a list of ordered pairs (word, count), where count shows how many times that word appears in the list.

For example, with the list

example_1 = ["apple","red","yellow","red"]

the wordCounter would produce a list with the following ordered pairs:

wordCounter example_1 = [("apple",1),("red", 2),("yellow",1)]

The order of the items in the answer list does not matter.

Detailed Explanation

In order to make the wordCounter function you will write a helper function updateCount that takes in a list of counts so far and updates the counts based on the new word. The example below shows a few steps of updating, starting with a list showing that “apple” and “red” have both been seen once time.

step1 = [("apple",1),("red",1)]

The next word in the example list above is “yellow”, so in step 2 below, you see that “yellow” is added with a count of one.

step2 = updateCount step1 "yellow"
check2 = step2 == [("apple",1),("red",1),("yellow",1)]

The last word in the example list is “red”. Since “red” is already in the list with a count of 1, the count is increased to 2.

step3 = updateCount step2 "red"
check3 = step3 == [("apple",1),("red",2),("yellow",1)]

Write the updateCount and wordCounter functions, as shown below. Write at least one convincing test for your wordCounter function.

Testing Code

Signatures and tests.

updateCount :: [(String,Int)] -> String -> [(String,Int)]
updateCount _ _ = []
-- if word is not seen, add (word,1) to list
-- if word is already seen, add 1 to its count
ce2 = [updateCount [("Not",4)] "Good" == [("Not",4),("Good",1)]
      ,updateCount [("Not",4)] "Not" == [("Not",5)]
      ]
wordCounter :: [String] -> [(String,Int)] -- you could just jump to your end goal
wordCounter _ = []
Last modified October 15, 2023: Added an example for top3By. (ab7c1ef)