Mutable Data structures? Why so hard to find

I can beat Python with this:

{-# LANGUAGE OverloadedStrings #-}

module CountWords where

import           Data.Foldable
import           Data.List       (sortBy)
import           Data.Ord        (Down (..), comparing)
import qualified Data.Text       as T
import qualified Data.Text.IO    as T

import qualified Data.Vector.Mutable as VM
import qualified Data.Vector.Unboxed.Mutable as UM
import qualified Data.Vector.Hashtables as H

import Control.Monad
import Control.Monad.Primitive
import System.IO

type HashTable k v = H.Dictionary (PrimState IO) VM.MVector k UM.MVector v

unlessM :: Monad m => m Bool -> m () -> m ()
unlessM m1 m2 = m1 >>= \b -> unless b m2

runCountWords :: IO ()
runCountWords = do
  t <- H.initialize 10000 :: IO (HashTable T.Text Int)
  let 
    go = unlessM isEOF $ do
      words <- T.words . T.toLower <$> T.getLine
      traverse_ (H.alter t (Just . maybe 1 (+ 1))) words
      go
  go
  xs <- sortBy (comparing (Down . snd)) <$> H.toList t
  traverse_ (\(w, i) -> T.putStrLn (w `T.append` " " `T.append` T.pack (show i))) xs

And @Bodigrim’s quick work improving toLower: https://github.com/haskell/text/pull/460

That gives me the following results:

Language      | Simple | Optimized | Notes
------------- | ------ | --------- | -----
Haskell       |   1.40 |           | by Adrien Glauser
Python        |   1.78 |      1.07 | 
4 Likes