为啥程序流控制随机执行

Posted

技术标签:

【中文标题】为啥程序流控制随机执行【英文标题】:Why program flow control executes randomly为什么程序流控制随机执行 【发布时间】:2017-08-23 21:46:11 【问题描述】:

我正在尝试通过编写一个简单的数学学习程序来同时学习数学和 Haskell。

开头是:

    生成随机数。 过滤这些数字以创建一个易于处理的问题。 显示问题然后接受我的回答 最后,它会将我的答案和正确答案交给另一个函数来给我反馈(“恭喜”--或--“抱歉,正确答案为空白)。

由于某种原因,祝贺功能结束后,它似乎随机选择了下一步,要么:

    它返回到 ma​​in(这是我期望它做的)。 或者在随机循环中,它会立即进入数学测试功能。发生这种情况时,上面的 步骤 2 不会发生,我开始在问题中得到小数。然后它可能会重复此步骤或返回 ma​​in

在尝试调试问题时,我会一直按 RETURN,它会在不同的时间发生。我还添加了一些调试“打印”语句。

这是程序中的 3 个函数。注意 main 调用 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 ""

这是我的调试输出。请注意,它提供小数的唯一时间是在 pause 结束后它没有立即返回 main 之后。

     __  __       _   _                          _   _         
    |  \/  | __ _| |_| |__   ___ _ __ ___   __ _| |_(_) ___ ___ 
    | |\/| |/ _` | __| '_ \ / _ \ '_ ` _ \ / _` | __| |/ __/ __|
    | |  | | (_| | |_| | | |  __/ | | | | | (_| | |_| | (__\__ 
    |_|  |_|\__,_|\__|_| |_|\___|_| |_| |_|\__,_|\__|_|\___|___/

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%"

如果有帮助,到目前为止我发现的唯一与远程相关的是:Second of several forked processes does not run in Haskell 。

最后,如果这有助于您制定答案,我就处于 Monads 的入门级。

如果任何人都可以提供任何帮助,我将不胜感激,了解发生了什么,id est,为什么它在 pause 结束后没有直接返回到 main,以及为什么它会跳过小数过滤器。

谢谢^^

【问题讨论】:

【参考方案1】:

funPercentOfNumberToAnother,你有这个子句:

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"

如果数字很难看,您的意图是回到函数的开头并重新开始;或者继续向用户显示数字。尽其所能,但问问你自己......这个if 子句的末尾会发生什么?在 thenelse 执行完毕后,无论如何都会执行不在 thenelse 分支中的内容。

所以,当你得到一些丑陋的数字时,你会开始一个递归调用,寻找更好的数字并显示它们。然后当递归调用完成时,你继续向用户显示原始的、丑陋的数字!

您将需要一个不同的控制流程,例如编写一个始终返回一个不难看的数字的函数,然后在您的(现在是非递归的)funPercentOfNumberToAnother 函数中使用它。或者您可以将函数主体的其余部分(向用户显示数字的部分)拉入 ifelse 部分,这样您就不会为丑陋的数字这样做。

【讨论】:

【参考方案2】:

根据 amalloy 的精彩解释,我了解发生了什么并修复了问题,然后测试了该问题。在 if 语句之外有代码:

if uglyAnswers
   then funPercentOfNumberToAnother
   else ...

当递归停止时,导致错误的答案后来下降。所以基本上我是在囤积它们。

也许这可以更好地解释它。看到我在第一次尝试时得到了一个干净的答案,所以它不必经过递归。第二次调用有两个电话,因为第一次电话找到了分数答案:

     __  __       _   _                          _   _         
    |  \/  | __ _| |_| |__   ___ _ __ ___   __ _| |_(_) ___ ___ 
    | |\/| |/ _` | __| '_ \ / _ \ '_ ` _ \ / _` | __| |/ __/ __|
    | |  | | (_| | |_| | | |  __/ | | | | | (_| | |_| | (__\__ 
    |_|  |_|\__,_|\__|_| |_|\___|_| |_| |_|\__,_|\__|_|\___|___/

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

这是来自原始问题的可行代码sn-ps:

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

【讨论】:

以上是关于为啥程序流控制随机执行的主要内容,如果未能解决你的问题,请参考以下文章

捕获异常作为预期的程序执行流控制?

[python]程序结构与控制流

代码混淆之道——控制流扁平与不透明谓词理论篇

Kotlin语法基础,控制流

Kotlin语法基础,控制流

第三讲:控制流:条件语句(上)