module WordsOp ( defaultWords , buildMapByLength , buildListLetterFrequency , buildMapWordsFrequency ) where import Control.Monad (liftM) import Data.Function (on) import Data.List (groupBy, sortBy, sort) import Data.Tuple (swap) import System.IO import qualified Data.Map as Map import System.Directory (doesFileExist) import Types defaultWordsFile :: FilePath defaultWordsFile = "../data/words.txt" -- | read the default words file. defaultWords :: IO WordDataSet defaultWords = readFileToWords defaultWordsFile readFileToWords :: FilePath -> IO WordDataSet readFileToWords fp = liftM wrapWordDataSet (readfile' fp) -- | Readfile if exists otherwise return empty. readfile' :: FilePath -> IO String readfile' fp = do e <- doesFileExist fp if e then readFile fp else return [] wrapWordDataSet :: String -- ^ File Content -> WordDataSet -- ^ Wrapped data set wrapWordDataSet [] = ([], Map.empty) wrapWordDataSet xs = let ws = lines xs in (ws, buildMapByLength ws) -- | FIXME: a little annoying that loop the groupBy result in order to get key for map. buildMapByLength :: [EnglishWord] -- ^ a alphabet sorted words list -> Map.Map Int [EnglishWord] buildMapByLength xs = Map.fromList [ (length $ head ys, ys) | ys <- group' $ sort' xs ] where sort' = sortBy (compare `on` length) group' = groupBy ((==) `on` length) englishAlp :: [Letter] englishAlp = "abcdefghijklmnopqrstuvwxyz" {- Splitted Word List by alphabet sequency. @param@ a sorted list that has words with same length. @return@ {"a": [...], "b":[...], ... } -} buildMapWordsFrequency :: [EnglishWord] -> MapPerAlphabet buildMapWordsFrequency ws = Map.mapWithKey f init where init = Map.fromList [ (x, []) | x <- englishAlp ] f k _ = [ b | b <- ws, k `elem` b] {- @param@ wordsObj :: {"a":[...], "b":[...], ...} @return@ list which elements are order by word frequency. e.g. ["c","a","b"] -} buildListLetterFrequency :: Map.Map Char [EnglishWord] -> [Letter] buildListLetterFrequency v = reverse $ map fst $ sortBy (compare `on` swap) $ Map.toList (Map.map length v)