递归haskell和堆栈溢出

递归haskell和堆栈溢出,haskell,Haskell,作为Haskell和函数式编程的新手,我主要来自Python背景,我想知道为什么以下函数会导致Haskell中的堆栈溢出,即使我使用非常低的数字,如4或5作为输入变量,而Python中完全相同的函数可以处理20及以上的整数而不会溢出。为什么会这样 countStairs <0 = 0 countStairs 0 = 1 countStairs n = countStairs(n-1) + countStairs(n-2) + countStairs(n-3) 我读过关于Haskell和堆

作为Haskell和函数式编程的新手,我主要来自Python背景,我想知道为什么以下函数会导致Haskell中的堆栈溢出,即使我使用非常低的数字,如4或5作为输入变量,而Python中完全相同的函数可以处理20及以上的整数而不会溢出。为什么会这样

countStairs <0 = 0
countStairs 0 = 1
countStairs n = countStairs(n-1) + countStairs(n-2) + countStairs(n-3)
我读过关于Haskell和堆栈溢出的其他响应,这些响应涉及代码优化和解决特定的溢出代码,而我感兴趣的是理解这两种语言在处理递归方面存在差异的具体原因,或者更一般地说,Haskell代码导致堆栈溢出的原因

编辑:我没有包括完整的python代码,因为这是我在堆栈溢出中的第一个问题,我正在努力找出如何使我的python正确格式化。顺便说一句,欢迎你们中的一些人。这里是,格式不好等等,但编写的python确实可以正确处理整数20,而我可怜的哈斯克尔却没有。我编辑了Haskell代码,以显示我最初省略的相应代码。我以为我包括了相关的递归部分,但显然我忽略了基本情况是错误的。尽管如此,如前所述,我的Haskell堆栈溢出而Python没有溢出,我仍然对了解原因感兴趣。尽管我没有编程背景,但我真的很喜欢学习Haskell,我只是想学习更多。感谢那些尽管我的问题不完整却试图解决这个问题的人

def countStairs(n):
    if n < 0:
        return 0
    elif n == 0:
        return 1
    else:
        return countStairs(n-1) + countStairs(n-2) + countStairs(n-3)

myint = int(raw_input("Please enter an integer: "))
print countStairs(myint)

对haskell不太熟悉,但看起来没有终止条件。我相信,随着n接近负无穷大,这将继续下去

尝试以下方法:

countStairs 0 = 1
countStairs n = countStairs(n-1) + countStairs(n-2) + countStairs(n-3)
这意味着countStairs0=1

如果您计划使用以下方法拨打countStairsn | n,您可能也需要担心负面消息:

countStairs n | n <= 0 = 1
countStairs n = countStairs(n-1) + countStairs(n-2) + countStairs(n-3)

…大约两秒钟后。因此,是的,科尔宾似乎是正确的。

添加终止条件的另一种方法是使用保护。这也解决了Python可以在不溢出堆栈的情况下运行无限递归,并且在有限时间内???@Rahul:嗯,它已经具有反重力。执行无限计算不会有那么难。@EricS.Bullington,因为这是一个常见的下一个错误,请注意,这两个错误都会发生。正如链接所示,添加-1并不困难,因为没有报告countStairs 20溢出的完全相同的python程序输出。巨大的堆栈跟踪非常有用;啊,没有意识到语法我的哈斯克尔知识是非常有限的:p。我非常喜欢这种语法(和C A McCann的),以及它比我自己的答案更好地捕捉了n=0以外的更多情况+1:@Corbin:该语法称为guards,|后面的位可以是任意布尔表达式。哦,否则就是标准图书馆提供的一种可爱的写作方式。哈斯克尔在我要学习的语言列表中,但我只是简单地看了一下:。@Corbin:你应该在可能的时候花点时间学习它;我自己也非常喜欢。我听说社区往往非常有帮助,尤其是在堆栈溢出方面啊,我知道一点阴谋,但从来没有搞乱过哈斯克尔。我发现函数式编程非常吸引人,希望将来能学到更多。我会记住你的建议:。一个需要三个连续的基本情况,否则它将成为一个无限递归。谢谢,科尔宾。我的完整程序有一个终止条件,但我犯了一个明显的错误,忽略了它。请参阅上面我的原始代码,仍然存在堆栈溢出。感谢您的认真回复。请参阅我上面编辑的代码,以回应您关于反重力的评论。看看你的回答,我重新编码了上面的Haskell,但是用了像你这样的守卫,而不是我用的那种模式匹配,它成功了。我想知道为什么。@EricS.Bullington:看亚当·瓦格纳的回答,你无意中重新定义了感谢你的解释。是的,我把警卫和模式匹配搞混了。我现在会小心地使用模式匹配与精确匹配。
∀x. x ⊢ countStairs 20
289329
countStairs n | n > 0 = countStairs(n-1) + countStairs(n-2) + countStairs(n-3)
              | otherwise = 1
countStairs < 0 = "Matched '< 0'"
countStairs   0 = "Matched '0'"
countStairs   n = "Matched n"

main = do
    putStrLn $ countStairs (-1)  -- outputs: "Matched n"
    putStrLn $ countStairs 0     -- outputs: "Matched 0"
    putStrLn $ countStairs 20    -- outputs: "Matched n"
(Main.<) :: Num a => t -> a -> [Char]
countStairs :: Num a => a -> [Char]
main :: IO ()
infix <
a < b = True

-- also defined as
(<) a b = True
(<) countStairs 0 = "Matched '< 0'"
*Main> 1 < 0

<interactive>:1:3:
    Ambiguous occurrence `<'
    It could refer to either `Main.<', defined at foo.hs:3:13
                          or `Prelude.<', imported from Prelude