簡體   English   中英

遞歸haskell和堆棧溢出

[英]Recursive haskell and stack overflow

作為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代碼,因為這是我在Stack Overflow中的第一個問題,我正在努力弄清楚如何正確設置Python格式(順便說一句,歡迎您,btw)。 在這里,格式設置很差,但在所有情況下,但編寫的Python確實可以與整數20一起正常工作,而我無疑可憐的Haskell卻不能。 我已經編輯了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)

添加終止條件的另一種方法是使用防護(這也解決了Corbin提到的<= 2條件:

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

更新資料

您更新的Haskell示例無效,因為您誤解了模式匹配的工作原理。 您期望它像警衛一樣工作(看到您試圖在模式匹配中提供一個< 0的布爾表達式),但是,該函數的版本從未匹配(當您調用countStairs函數時)。 考慮以下示例:

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"

有趣的是,您的函數實際上可以編譯。 要找出原因,請將上面的代碼加載到ghci中,然后輸入:browse 這將為您提供在此模塊中定義的功能的列表。 您應該會看到以下內容:

(Main.<) :: Num a => t -> a -> [Char]
countStairs :: Num a => a -> [Char]
main :: IO ()

您有countStairsmain都有意義。 但是您還具有稱為Main.<此功能。 這是什么? 您已經在此模塊中重新定義了<函數! 如果您不熟悉,則可以這樣定義infix函數(例如+<>等):

infix <
a < b = True

-- also defined as
(<) a b = True

通常,您需要該infix FUNCTION_NAME來指示您的函數為中綴。 但是..前奏已經將<定義為infix函數,因此,您不需要,而是只給自己定義了<

現在,讓我們重新排列countStairs < 0 = "Matched '< 0'"就像我們對a < b所做的那樣,您會得到:

(<) countStairs 0 = "Matched '< 0'"

在此函數中, countStairs實際上是<函數的第一個參數。

這是進一步說明這一點的另一個示例。 嘗試在ghci中運行1 < 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

通常,您會得到False ,但是在這種情況下,ghci不知道是否應使用您的函數(因為<只是一個常規函數,不是一種特殊的語法)或內置的(Prelude)版本<

長話短說...使用警衛(或caseif )進行布爾測試,而不是模式匹配。

對Haskell不太熟悉,但是看起來沒有終止條件。 我相信,隨着n接近負無窮大,這將繼續下去。

嘗試類似:

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

這意味着countStairs(0)= 1。

如果您計划致電countStairs(n)|您可能還需要擔心負面因素。 n <= 2。

使用這個:

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

在GHCi中給我這個:

∀x. x ⊢ countStairs 20
289329

...大約兩秒鍾 是的,Corbin似乎是正確的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM