word_freq.hs in Haskell
Counts word frequencies across an inline passage and prints the top eight with totals.
import Data.Char (isAlpha, toLower)
import Data.List (sortOn)
import Data.Map.Strict (Map)
import Data.Ord (Down (..))
import qualified Data.Map.Strict as Map
passage :: String
passage = unwords
[ "The tide goes out and the tide comes in."
, "The boats wait for the tide, and the gulls wait for the boats."
, "Out on the flats the light goes flat and the mud goes silver."
]
-- Lowercase everything, then treat any non-letter as a separator.
normalize :: String -> [String]
normalize = words . map keep
where
keep c
| isAlpha c = toLower c
| otherwise = ' '
-- fromListWith folds the values of duplicate keys together.
tally :: [String] -> Map String Int
tally ws = Map.fromListWith (+) [(w, 1) | w <- ws]
-- Down on the count sorts descending; the word settles ties.
ranked :: Map String Int -> [(String, Int)]
ranked = sortOn (\(w, n) -> (Down n, w)) . Map.toList
pad :: Int -> String -> String
pad n s = s ++ replicate (n - length s) ' '
lpad :: Int -> String -> String
lpad n s = replicate (n - length s) ' ' ++ s
row :: (String, Int) -> String
row (w, n) = pad 10 w ++ lpad 6 (show n)
rule :: String
rule = replicate 16 '-'
main :: IO ()
main = do
let ws = normalize passage
counts = tally ws
putStrLn "word frequency, top 8"
putStrLn (pad 10 "word" ++ lpad 6 "count")
putStrLn rule
mapM_ (putStrLn . row) (take 8 (ranked counts))
putStrLn rule
putStrLn (pad 10 "distinct" ++ lpad 6 (show (Map.size counts)))
putStrLn (pad 10 "total" ++ lpad 6 (show (length ws)))
How it works
normalizelowercases letters and blanks out everything else beforewordssplits the passage.tallybuilds aMap String IntwithMap.fromListWith (+), which folds duplicate keys together.rankedsorts onDown nso counts descend, androwlays out each line aspad 10 w ++ lpad 6 (show n).
Keywords and builtins used here
DownIOIntMapStringasdoimportisAlphaletlpadmainnormalizepadpassagequalifiedrankedrowrulesortOntallytoLowerwhere
The run, in numbers
- Lines
- 52
- Characters to type
- 1477
- Tokens
- 308
- Three-star pace
- 75 tpm
At the three-star pace of 75 tokens a minute, this run takes about 246 seconds.
Step 1 of 3 in Encore, step 25 of 27 in Language basics.