1

Working on terminal based app that uses a number of putStr/getLine's for gathering user input. Would like to use the following function to shorten the tedious putStr getLine by feeding it a list of questions and returning the answers in a list (recursively). Although the getLines terminate nicely, I cannot avoid the non-exhaustive patterns on the putStr side of things. This is not a duplicate. Multiple getLine's can be done using replicateM, but it's the combination of questions/answers I am after.

(***) = hFlush stdout

questionnaire :: [String] -> IO [String]
questionnaire (x:xs) = do
    putStr x
    (***) 
    user <- getLine
    case user of 
        "" -> return []
        _  -> do
            nextUser <- questionnaire xs
            return (user : nextUser)
Madderote
  • 1,107
  • 10
  • 19

1 Answers1

2

You don't actually need explicit recursion here, making it impossible to forget to define questionaire when its argument is an empty list.

questionaire :: [String] -> IO [String]
questionaire  = traverse getWithPrompt
  where getWithPrompt x = do
            putStr x
            (***)
            getLine

Example:

> users <- questionaire ["name? ", "name? ", "name? "]
name? alice
name? bob
name? charlie
> users
["alice","bob","charlie"]

getWithPrompt has type String -> IO String. traverse is a little like map, except where map getWithPrompt prompts would leave you with a value of type [IO String], traverse combines the list of IO actions into a single IO action which executes each IO action and gathers their results into a single list.


As pointed out by Daniel Wagner, I forgot about stopping if the empty string is entered. To handle that, we can go back to your original recursion, but remembering to define what questionnaire [] means.

questionnaire :: [String] -> IO [String]
questionnaire [] = return []
questionnaire (x:xs) = do
    putStr x
    (***) 
    user <- getLine
    case user of 
        "" -> return []
        _  -> do
            nextUser <- questionnaire xs
            return (user : nextUser)
chepner
  • 497,756
  • 71
  • 530
  • 681