Untitled

mail@pastecode.io avatar
unknown
haskell
3 years ago
3.2 kB
2
Indexable
Never
module Ch11.Phone where
import Data.Char (toLower, isUpper)
import Data.List (group, sort)
import Ch11.Adt (splitWords)

data Key = One
    | Star
    | TextKey Char [Char]

instance Show Key where
    show One = "1"
    show Star = "*"
    show (TextKey c _) = c : ""

type Phone = [Key]

phoneKb :: Phone
phoneKb = [One, Star, TextKey '#' ".,",
      TextKey '2' "abc", TextKey '3' "def", TextKey '4' "ghi"
    , TextKey '5' "jkl", TextKey '6' "mno", TextKey '7' "pqrs"
    , TextKey '8' "tuv", TextKey '9' "wxyz", TextKey '0' "+ _"
    ]

type Presses = Int

-- function names are retarded, I kept the ones from the book

-- calculate key sequence to press to reach to given character
reverseTaps :: Phone -> Char -> [(Key, Presses)]
reverseTaps kb c
  | isUpper c = (Star, 1) : [(letterPresses kb $ toLower c)]
  | otherwise = [letterPresses kb c]

-- guaranteed to be lowercase
letterPresses :: Phone -> Char -> (Key, Presses)
letterPresses kb c = case find (matchSeq c) $ concat $ map charSeqs kb of
    -- function is not complete, but this is what exercise signature wants to
    Nothing -> error "invalid character"
    Just (k, _, n) -> (k, n)
        
find :: (a -> Bool) -> [a] -> Maybe a
find _ [] = Nothing
find p (x:xs)
  | p x = Just x
  | otherwise = find p xs

-- matches given character with given keypress sequence,
-- return True if the char in the seq is the same as given char
matchSeq :: Char -> (Key, Char, Presses) -> Bool
matchSeq c (_, c', _) = c == c'

-- all possible tap sequences for a given key, resulting in different characters
-- each tuple is: (k, c, n) where k is key to press, c is character that
-- will result from it and n is a number of presses required
charSeqs :: Key -> [(Key, Char, Presses)]
charSeqs One = []
charSeqs Star = []
charSeqs k@(TextKey digit letters) = zip3 (repeat k) allLetters presses where
    allLetters = letters ++ [digit]
    presses = [1..(length allLetters)]

-- calculate key sequence to press to print given string
cellPhonesDead :: Phone -> String -> [(Key, Presses)]
cellPhonesDead kb s = concat $ map (reverseTaps kb) s

-- get total number of taps in a sequence
fingerTaps :: [(Key, Presses)] -> Presses
fingerTaps ks = foldr (+) 0 $ map snd ks

-- most frequent letter in a string
mostPopularLetter :: String -> Char
mostPopularLetter "" = error "empty string"
mostPopularLetter s = findMostFrequent s

findMostFrequent :: Ord a => [a] -> a
findMostFrequent [] = error "empty list"
findMostFrequent xs@(x:_) = snd $ foldr max (1, x) freqs where
    freq cs = (length cs, head cs)
    freqs = map freq $ group $ sort xs

-- most frequent letter in a list of strings
coolestLetter :: [String] -> Char
coolestLetter ss = mostPopularLetter $ concat ss

-- most frequent word in a list of strings
coolestWord :: [String] -> String
coolestWord ss = findMostFrequent totalWords where
    totalWords = concat $ map splitWords ss

convo :: [String]
convo =
    ["Wanna play 20 questions",
    "Ya",
    "U 1st haha",
    "Lol ok. Have u ever tasted alcohol",
    "Lol ya",
    "Wow ur cool haha. Ur turn",
    "Ok. Do u think I am pretty Lol",
    "Lol ya",
    "Just making sure rofl ur turn"]