typestar

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

  1. normalize lowercases letters and blanks out everything else before words splits the passage.
  2. tally builds a Map String Int with Map.fromListWith (+), which folds duplicate keys together.
  3. ranked sorts on Down n so counts descend, and row lays out each line as pad 10 w ++ lpad 6 (show n).

Keywords and builtins used here

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.

Type this snippet

Step 1 of 3 in Encore, step 25 of 27 in Language basics.

← Previous Next →