I'm trying by doing to learn some Haskell, but have run into an issue i have no clue how to even explain. The problem point is some code to handle letting the user pick the order to visit menu options, and changing their options as often as they like before confirming. The first choice goes smooth, and subsequent selections of the same option do too, but as soon as a different selection is made, every loop from that point, regardless of whether 1 or 2 is input, the execution will go down both of the options in the function modeSelectParse (See code below). Those branches are the only calls to either of gatherSettings or mart in the program, and this behaviour persisted even when they were both stubbed out to just a print statement.
When i added more branches, all previously visited branches are run once on each iteration, in a fixed order all the time regardless of my shuffling around the order of the branches in modeSelectParse, or what number corresponds to what option.
I suspected stdin buffering being at fault, so i have tried turning that off, and various other tests on the input i got in. But nothing seemed off about the data when i tried printing it at various points in the program either.
The initial call to modeSelectInit is also not in a place where it could ever end up called more than once.
I can give more explanation and code if needed.
modeSelectInit :: DatabaseStruct -> IO (IO Settings, IO Order)
modeSelectInit db = do
putStrLn "A lot of text"
hFlush stdout
let select = (return emptySettings, return [])
input <- awaitChar ['1', '2']
modeSelect db (modeSelectParse db input select)
modeSelect :: DatabaseStruct -> (IO Settings, IO Order) -> IO (IO Settings, IO Order)
modeSelect db select = do
settings <- fst select
order <- snd select
putStrLn "A lot of text"
hFlush stdout
input <- awaitChar ['1', '2', '3']
if input == '3'
then return select
else modeSelect (modeSelectParse db input select)
modeSelectParse :: DatabaseStruct -> Char -> (IO Settings, IO Order) -> (IO Settings, IO Order)
modeSelectParse db '1' (_, o) = (gatherSettings, o)
modeSelectParse db '2' (s, _) = (s, mart db)
awaitChar :: [Char] -> IO Char
awaitChar chars = do
input <- getLine
awaitChar2 input chars
awaitChar2 :: String -> [Char] -> IO Char
awaitChar2 [] chars = awaitChar chars
awaitChar2 (x: _) chars = ifThenElse (x `elem` chars) (return x) (awaitChar chars)
Both passing IO
actions as arguments and returning nested IO
actions are very unusual. (There are of course situations where that's exactly what needed, but it is not in 99% of standard, run-of-the-mill, day-to-day Haskell.) I suspect just eliminating that oddity will take care of your problem. So, try these type signatures instead:
modeSelectInit :: DatabaseStruct -> IO (Settings, Order)
modeSelect :: DatabaseStruct -> (Settings, Order) -> IO (Settings, Order)
modeSelectParse :: DatabaseStruct -> Char -> (Settings, Order) -> IO (Settings, Order)
Their implementations will have to be tweaked slightly to compensate, but I suspect from what I see here that you know roughly how to do that. (But if that feels hard, then definitely say -- many people here would be happy to say exactly how if you find yourself feeling stuck!)