hashmap withdrawal and poor haskell style

Dean Herington heringto@cs.unc.edu
Wed, 03 Apr 2002 10:46:43 -0500


Michal,

As Daan Leijen has suggested, `accumArray` is probably the best solution to your simple
histogramming problem.  However, you might also be interested to learn about "finite maps", which
are often the appropriate functional analogue to "hash maps".  Finite maps are typically
implemented with balanced trees and exhibit O(log n) time cost for insertion and lookup.  (The
extra cost over imperative languages' O(1) cost is the price paid for persistence.)  The following
version of your program runs on Hugs 98 and GHC.  (For GHC you must specify "-package data" to
access the `FiniteMap` module.)

> import Char (isAlpha, toLower)
> import FiniteMap

> main :: IO ()
> main = interact (report . histogram)

> type Histo = FiniteMap Char Int

> histogram :: String -> Histo
> histogram = foldl tally emptyFM

> tally :: Histo -> Char -> Histo
> tally histo ch = if isAlpha ch then addToFM_C (+) histo (toLower ch) 1
>                                else histo

> report :: Histo -> String
> report histo = unlines [ line ch | ch <- ['a'..'z'] ]
>  where line ch = ch : " " ++ replicate (count ch) '*'
>        count ch = lookupWithDefaultFM histo 0 ch

Dean Herington