ну и все, засовывай это в стейт, получай
type Seed = Int
type Random = State Seed
random' :: Seed -> (Int, Seed)
runRandom :: Seed -> Random a -> a
runRandom = flip evalState
randomInt :: Random Int
randomInt = state random'
randomBy :: Int -> Random Int
randomBy n = fmap (\x -> rem x n) randomInt
randomOf :: [a] -> Random a
randomOf xs = do
  i <- randomBy (length xs)
  pure (xs !! i)
randomChar :: Random Char
randomChar = randomOf ['a'..'z']
randomString :: Random String
randomString = do
  len <- randomBy 50
  replicateM len randomChar
data User = User { name :: String, age :: Int }
randomUser :: Random User
randomUser = do
  name <- randomString
  age <- randomBy 30 -- старше людей не бывает
  pure User {name, age}
generateUsers :: IO [User]
generateUsers = do
  seed <- read <$> readFile "/dev/urandom" -- или как там это сделать правильно
  pure $ runRandom seed (replicateM 10 randomUser)