A generalization for #9 . The choices can be modeled as their display name coupled with a parsing function to the desired data type of the answer: ```haskell data MultipleChoiceOption a = MultipleChoiceOption { displayName :: ByteString , parsingFun :: ByteString -> Maybe a } ``` Then, we can model multiple choices as: a message prompt, a non-empty list of choices (whose default choice will always be the head), and a value for the default option: ``` data MultipleChoicePrompt a = MultipleChoicePrompt { promptMessage :: ByteString , promptOptions :: NonEmpty (MultipleChoiceOption a) , defaultValue :: a } ``` Thus, the following prompt data: ```haskell MultipleChoicePrompt { promptMessage="Are you sure?" , promptOptions= MultipleChoiceOption { displayName="y" , parsingFun = \s -> if s == "y" then Just Yes else Nothing } :| [ MultipleChoiceOption { displayName="n" , parsingFun = \s -> if s == "n" then Just No else Nothing } ] , defaultValue=Yes } ``` Will represent: ```haskell Are you sure? [y]/n ``` Finally, we can define a function that: - Prints the question (via an aux function that takes the `MultipleChoicePrompt` - Reads answer - Returns the first choice that is parsed correctly (can be done with a `foldMap` over the `Alt` monoid) - Or prints an error message to `stderr` in case of error, returning `Nothing` ```haskell multipleChoiceQuestion :: MonadIO m => MultipleChoicePrompt a -> m (Maybe a) ``` An example run would be: ```haskell >>> multipleChoiceQuestion MultipleChoicePrompt { promptMessage="Are you sure?" , promptOptions= MultipleChoiceOption { displayName="y" , parsingFun = \s -> if s == "y" then Just Yes else Nothing } :| [ MultipleChoiceOption { displayName="n" , parsingFun = \s -> if s == "n" then Just No else Nothing } , MultipleChoiceOption { displayName="cancel" , parsingFun = \s -> if s == "cancel" then Just Cancel else Nothing } ] , defaultValue=Yes } >>> n Just No ``` Something to notice is that the function will take the default value and build a parser to accept empty responses: ```haskell >>> multipleChoiceQuestion MultipleChoicePrompt { promptMessage="Are you sure?" , promptOptions= MultipleChoiceOption { displayName="y" , parsingFun = \s -> if s == "y" then Just Yes else Nothing } :| [ MultipleChoiceOption { displayName="n" , parsingFun = \s -> if s == "n" then Just No else Nothing } , MultipleChoiceOption { displayName="cancel" , parsingFun = \s -> if s == "cancel" then Just Cancel else Nothing } ] , defaultValue=Yes } >>> Just Yes ``` Finally, some points that might need refinement: - Default value might be different than the value that is returned by the parsing function. - Instead of printing to `stderr` and returning `Nothing`, it may be better to return `Either Bytestring a` and let another function decide what to do. - Instead of having a `Non-Empty` List, we could have either a tuple with the first two options and a normal `List` for the rest, or a sized container (i.e, something from [Data.Size](https://hackage.haskell.org/package/sized-1.0.0.1/docs/Data-Sized.html)). Having a multiple option question with just one option feels wrong. I'm willing to try and accommodate all suggestions to this implementation :)
This issue appears to be discussing a feature request or bug report related to the repository. Based on the content, it seems to be still under discussion. The issue was opened by initial-mockingbird and has received 3 comments.