2015-05-07 47 views
6

我遇到了Haskell中的無限循環問題,無法理解原因是什麼。我有三個版本的下面相同的代碼。第一個會導致無限循環,而後兩者不會。這是遞歸生成數組的一些基本設計的代碼。在這種情況下,它只有三個項目,而唯一的遞歸調用是第三個項目,它選擇前兩個中較大的項目。 if a > b聲明似乎導致循環(但後來我表明它不能是原因)。奇怪<<loop>>數組生成異常

import Data.Array 

main :: IO() 
main = print grid 
    where grid = array (0, 2) $ map func [0 .. 2] 
     func i 
      | i == 2 = let a = grid ! (i - 1) 
          b = grid ! (i - 2) 
         in if a > b 
           then (i, a) 
           else (i, b) 
      | otherwise = (i, 0) 

在接下來的版本中,我簡單地使用max a b代替if聲明。這裏沒有循環。

main :: IO() 
main = print grid 
    where grid = array (0, 2) $ map func [0 .. 2] 
     func i 
      | i == 2 = let a = grid ! (i - 1) 
          b = grid ! (i - 2) 
         in (i, max a b) 
      | otherwise = (i, 0) 

在接下來的版本中,我不斷的,而不是從func返回一個元組的ifzip指數。這一個也運行良好。

main :: IO() 
main = print grid 
    where grid = array (0, 2) $ zip [0 .. 2] $ map func [0 .. 2] 
     func i 
      | i == 2 = let a = grid ! (i - 1) 
          b = grid ! (i - 2) 
         in if a > b 
           then a 
           else b 
      | otherwise = 0 

這兩個其他情況似乎表明,與遞歸定義或使用if語句沒有問題。

作爲循環的原因是什麼呢?

+0

順便提一句,這個問題的說法絕對完美:只要有足夠的代碼來觀察問題,再加上一些在他們面前完全相互矛盾的觀察。再加上你認爲可能是問題和證據的明確輪廓。四周只是一個可愛的謎題。 –

回答

6

這是一個有趣的觀察:在(i, max a b),我們知道(在計算ab之前)該元組在其第一個組件中有i。同樣,在您的zip代碼中,我們可以觀察到元組的第一部分是0,12,而不計算元組的第二部分。但是,在if a > b then (i, a) else (i, b)中,它是而不是很明顯,我們在第一部分中有一個帶有i的元組:如果a > b是底部,則表達式的結果是底部,而不是第一部分中帶有i的元組!

這很重要,因爲計算a > b需要計算a,這需要知道哪些值是在該陣列,其需要知道是否i是在所映射的列表的最後一個元件0(並且因此應當覆蓋以前0值在位置0 ) - 一個循環。

一個解決辦法是解除if的(i, _)部分,並使用(i, if a > b then a else b)。這實質上就是你的max解決方案。

相關問題