簡體   English   中英

Haskell - C棧溢出

[英]Haskell - C stack overflow

我剛剛被介紹給Haskell,所以我對如何使用該語言進行編碼並不是很熟練,因此,如果這是重復的話,對不起,但是我不理解用該語言編寫的其他代碼。

我正在嘗試編寫一個算法,該算法將采用不超過給定值的正整數甚至整數的總和。 我試圖編寫代碼但是我一直在收到C堆棧溢出錯誤。

這是我的代碼:

sumint :: Int -> Int
sumint x
  | x==0 = 0  
  | x==1 = 1
  | (x `mod` 2 == 0) && (x >= 2) = x + (sumint x-2)
  | (x `mod` 2 /= 0) && (x >= 1) = x + (sumint x-1)

我錯在哪里得到這個錯誤?

初始錯誤:無限遞歸

單步執行代碼:

sumint :: Int -> Int

嘿,類型簽名。 你搖滾。

sumint x
  | x==0 = 0

一個基礎案例,很酷。

  | x==1 = 1

完全沒必要的情況。 好的,確定......除外。 1甚至不是為什么我們將它包含在總和中? 它應該為零(或完全刪除)。

  | (x `mod` 2 == 0) && (x >= 2) = x + (sumint x-2)

這個問題的關鍵在這里。 X甚至很棒。 2. X是正面的,是的。 結果是x + (sumint x) - 2不!

  • 錯誤1:注意函數應用程序比運算符更嚴格,因此應該是x + sumint (x-2)

這就是堆棧溢出的原因。 sumint 2 == 2 + (sumint 2) - 2 + (sumint 2) -2 + (sumint 2) -2 + ... ,yay無限遞歸。

  | (x `mod` 2 /= 0) && (x >= 1) = x + (sumint x-1)

另一種情況......賠率......積極......但為什么我們加入x? 你想添加平均值,而不是賠率。 因此,在我們得到的同時解決上述問題:

  • 錯誤2:如果確定x是奇數,請不要添加x 只需使用sumint (x-1)

那你就沒有了。 如果x不是正數,會發生什么? 你需要(另一個)案例。

| otherwise = 0

下一期:沒有積累

現在的問題是你正在構建一個大的thunk(未評估的計算),而不是通過在進展時累積結果來在恆定的空間中操作。 請注意,如果我們擴展你的計算,比如6,我們得到:

sumint 6 = 6 + sumint (6-2) 
      = 6 + 4 + sumint (4-2)
      = 6 + 4 + 2 + sumint (2-2)
      = 6 + 4 + 2 + 0

你真的不希望將所有這些添加內容分開,最好傳入一個累加器,例如:

sumint x = go x 0
 where
  go n accumulator
         | n <= 0    = accumulator
         | odd n     = go (n-1) accumulator
         | otherwise = go (n-2) (accumulator + n)

旁注:其他stackoverflow公民可能會提到使累加器嚴格,這是一個很好的形式。 我不想通過這里的討論分散當前提問者的注意力。 注意使用優化, -O2就足夠了。

慣用解決方案

以上所有解決方案都相當冗長。 使用函數和累加器迭代列表的一般操作是一種fold Fold是函數式編程中常見的眾多高度優化的結構遍歷之一。 在這種情況下,“嚴格左側折疊”是典型的候選者(來自Data.List )。 這就是foldl' '按照慣例foldl' '( ' )意味着它是嚴格的而l意味着離開。

sumint n = foldl' (+) 0 [val | val <- [0..n], even val]

在這里,我們折疊在列表上以獲得我們的總和。 要創建感興趣的列表中,我們使用列表理解-首先從枚舉值0..n ,並跳過不符合謂詞任何價值even

我們可以通過使用步長為2的sum函數和列表推導來進一步清理它並改進它,從而只給出我們想要的平均值:

sumint n = sum [0,2..n]

它是運算符優先級問題。 在Haskell中,函數應用程序具有最高可能的優先級。 因此,當你寫sumint x - 2 ,即使你將它解釋為sumint (x-2) ,Haskell也將它解釋為(sumint x) - 2 因此-您正在嘗試定義sumint x直接來講sumint x -這只是堆積起來的遞歸函數調用,直到堆棧溢出。 如果要在函數應用程序之前評估減法,則需要添加顯式括號。

暫無
暫無

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

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