Basic random password generator
hlint

You should run hlint on your program - it's a good way to become
familiar with techniques and practices used by expert Haskellers.

Running hlint on your code returned the following suggestions:

* use camelCase instead of underscores

./passwd.hs:7:20: Warning: Redundant bracket
Found:
  (randomRIO (lo, hi) :: IO Int)
Why not:
  randomRIO (lo, hi) :: IO Int

./passwd.hs:19:5: Error: Use mapM
Found:
  sequence $ map (\ x -&gt; random_char) [1 .. length]
Why not:
  mapM (\ x -&gt; random_char) [1 .. length]

./passwd.hs:19:21: Warning: Use const
Found:
  \ x -&gt; random_char
Why not:
  const random_char


sequence . map

You're right that the code for random_passwd feels hacky since
the value x is ignored. The canonical way to write this is:

import Control.Monad (replicateM)

random_passwd = replicateM length random_char


replicateM repeats a monadic action a specified number of times collecting the
results in a list.

!!

You probably already know that using !! to index into a list
is inefficient. A better data structure to use for alphabet is
Text from Data.Text which gives you O(1) indexing.

import qualified Data.Text as T

alphabet = T.pack $ ['A'..'Z'] ++ ['a'..'z'] ++ ...

random_char = do
  index &lt;- randomR (0, T.length alphabet - 1)
  return $ T.index alpha index