Why program flow control is performed randomly

I am trying to learn math and Haskell at the same time by programming a simple math tutorial.

It starts with:

  • Random number generation.
  • Filters these numbers to create an easy problem to work with.
  • Show a question, then answer.
  • Finally, it conveys both my answer and the correct answer to another function to give me feedback ("Congratulations" - or-- "Sorry, the correct answer is BLANK).

For some reason, after completing the congratulation function, it seems to randomly choose where it goes next:

  • He returns to main (this is what I expect from him).
  • Or in random cycles, it immediately switches to the math test function. When this happens, step 2 above does not happen, and I start getting fractional numbers in the question. Then he can repeat this step or return to main .

While trying to debug the problem, I just keep hitting RETURN and it will happen at different times. I also added some debug statements "print".

Here are 3 functions from the program. Note that the main calls to funPercentOfNumberToAnother:

funPercentOfNumberToAnother :: IO () funPercentOfNumberToAnother = do (percentDec, percentStr) <- getPercent ofNum <- getDecimal (200 :: Decimal) let isNum = percentDec * ofNum if uglyAnswers ([ofNum, isNum], [percentDec]) then do putStrLn ("ofNum: " ++ show ofNum) putStrLn ("isNum: " ++ show isNum) putStrLn "___________________________" funPercentOfNumberToAnother else do putStrLn ("ofNum: " ++ show ofNum) putStrLn ("isNum: " ++ show isNum) putStrLn "Percents" -- putStrLn "\n\n" putStrLn (show isNum ++ " is what percent of " ++ show ofNum ++ "?\n" ) putStr "> " ans <- getLine submitStringAnswer (ans, percentStr ++ "%") submitStringAnswer :: (String, String) -> IO () submitStringAnswer (myAns, correctAns) = do if myAns == correctAns then putStrLn "Congratz!" else do putStrLn ("Sorry the correct answer is: " ++ show correctAns) pause pause :: IO () pause = do x <- getLine putStrLn "" 

Here is my debug output. Please note that the only time he gives fractional numbers is after he does not return to the main one immediately after the end of the pause .

  __ __ _ _ _ _ | \/ | __ _| |_| |__ ___ _ __ ___ __ _| |_(_) ___ ___ | |\/| |/ _` | __| '_ \ / _ \ '_ ` _ \ / _` | __| |/ __/ __| | | | | (_| | |_| | | | __/ | | | | | (_| | |_| | (__\__ |_| |_|\__,_|\__|_| |_|\___|_| |_| |_|\__,_|\__|_|\___|___/ 1.) Learn Math 2.) Math Lookup 3.) Quit Excolo 1 ofNum: 35 isNum: 15.75 ___________________________ ofNum: 120 isNum: 102 Percents 102 is what percent of 120? > Sorry the correct answer is: "85%" 15.75 is what percent of 35? > Sorry the correct answer is: "45%" __ __ _ _ _ _ | \/ | __ _| |_| |__ ___ _ __ ___ __ _| |_(_) ___ ___ | |\/| |/ _` | __| '_ \ / _ \ '_ ` _ \ / _` | __| |/ __/ __| | | | | (_| | |_| | | | __/ | | | | | (_| | |_| | (__\__ |_| |_|\__,_|\__|_| |_|\___|_| |_| |_|\__,_|\__|_|\___|___/ 1.) Learn Math 2.) Math Lookup 3.) Quit Excolo 1 ofNum: 80 isNum: 44 Percents 44 is what percent of 80? > Sorry the correct answer is: "55%" __ __ _ _ _ _ | \/ | __ _| |_| |__ ___ _ __ ___ __ _| |_(_) ___ ___ | |\/| |/ _` | __| '_ \ / _ \ '_ ` _ \ / _` | __| |/ __/ __| | | | | (_| | |_| | | | __/ | | | | | (_| | |_| | (__\__ |_| |_|\__,_|\__|_| |_|\___|_| |_| |_|\__,_|\__|_|\___|___/ 1.) Learn Math 2.) Math Lookup 3.) Quit Excolo 1 ofNum: 15 isNum: 2.25 ___________________________ ofNum: 60 isNum: 0.6 ___________________________ ofNum: 40 isNum: 30 Percents 30 is what percent of 40? > Sorry the correct answer is: "75%" 0.6 is what percent of 60? > Sorry the correct answer is: "1%" 2.25 is what percent of 15? > Sorry the correct answer is: "15%" 

If this helps, the only thing that is remotely relevant is what I have found so far: The second of several forked processes does not start in Haskell .

Finally, I am right at the entry-level Monads if this helps formulate your answer.

I would be grateful for any help that anyone can give regarding what is happening, id est, why he doesn’t return directly to the main thing after the pause is over, and why he skips the fractional filter.

Thanks ^^

+5
source share
2 answers

In funPercentOfNumberToAnother you have this sentence:

 if uglyAnswers ([ofNum, isNum], [percentDec]) then do putStrLn ("ofNum: " ++ show ofNum) putStrLn ("isNum: " ++ show isNum) putStrLn "___________________________" funPercentOfNumberToAnother else do putStrLn ("ofNum: " ++ show ofNum) putStrLn ("isNum: " ++ show isNum) putStrLn "Percents" 

Your intention is to return to the beginning of the function and start all over again if the numbers are ugly; or otherwise continue to show numbers to the user. It works as much as possible, but ask yourself ... what happens at the end of this if ? Material that is not in the then or else branches is executed regardless of whether then or else is being executed.

So, when you get some ugly numbers, you start a recursive call that searches for the best numbers and displays them. Then, when this recursive call is completed, you continue to show the user the original, ugly numbers anyway!

Here you will need another control flow, for example, write a function that always returns a non-ugly number, and then just use this in your (now non-recursive) function funPercentOfNumberToAnother . Or you can stretch the rest of the body of the function, the part that shows the numbers to the user, to the else part of the if , so you do not do this for numbers that are ugly.

+7
source

According to a huge explanation, I realized what was going on and corrected, and then checked the problem. Having code outside the if statement:

 if uglyAnswers then funPercentOfNumberToAnother else ... 

triggered unsuccessful responses to lower later when the recursion stopped. So, in fact, I stocked them up.

Perhaps this may explain it better. See that I got a clean answer on the first try, so he didn't have to go through the recursion. There were two calls for the second move, because the first call found a fractional answer:

  __ __ _ _ _ _ | \/ | __ _| |_| |__ ___ _ __ ___ __ _| |_(_) ___ ___ | |\/| |/ _` | __| '_ \ / _ \ '_ ` _ \ / _` | __| |/ __/ __| | | | | (_| | |_| | | | __/ | | | | | (_| | |_| | (__\__ |_| |_|\__,_|\__|_| |_|\___|_| |_| |_|\__,_|\__|_|\___|___/ 1.) Learn Math 2.) Math Lookup 3.) Quit Excolo 1 In the else statement =================================== Finally outside the else statement ofNum: 10 isNum: 4 __ __ _ _ _ _ | \/ | __ _| |_| |__ ___ _ __ ___ __ _| |_(_) ___ ___ | |\/| |/ _` | __| '_ \ / _ \ '_ ` _ \ / _` | __| |/ __/ __| | | | | (_| | |_| | | | __/ | | | | | (_| | |_| | (__\__ |_| |_|\__,_|\__|_| |_|\___|_| |_| |_|\__,_|\__|_|\___|___/ 1.) Learn Math 2.) Math Lookup 3.) Quit Excolo 1 Bad answer alert! =================================== In the else statement =================================== Finally outside the else statement ofNum: 160 isNum: 80 =================================== Finally outside the else statement ofNum: 55 isNum: 0.55 

Here are the processed code fragments from the original question:

 funPercentOfNumberToAnother :: IO () funPercentOfNumberToAnother = do (percentDec, percentStr) <- getPercent ofNum <- getDecimal (200 :: Decimal) let isNum = percentDec * ofNum if uglyAnswers ([ofNum, isNum], [percentDec]) then funPercentOfNumberToAnother else do let message = show isNum ++ " is what percent of " ++ show ofNum ++ "?\n" testProblem (percentStr ++ "%", message) testProblem :: (String, String) -> IO () testProblem (correctAns, message) = do putStrLn message putStrLn "\n\n" putStr "> " myAns <- getLine if myAns == correctAns then putStrLn "Congratz!" else do putStrLn ("Sorry the correct answer is: " ++ show correctAns) pause 
0
source

Source: https://habr.com/ru/post/1271169/


All Articles