2014-10-02 75 views
2

我的目標是編寫一個函數來計算低於特定數字'n'的最大Collat​​z數。 (對於那些熟悉的人來說,這是個項目歐拉問題。)Haskell初學者:「沒有......因...而產生的錯誤」錯誤

某些上下文:給定整數的Collat​​z數等於該整數的Collat​​z序列的長度。一個整數的Collat​​z序列計算如下:序列中的第一個數字(「n0」)是該整數本身;如果n0是偶數,序列中的下一個數字(「n1」)等於n/2;如果n0是奇數,那麼n1等於3 * n0 + 1。我們繼續遞歸地擴展序列直到我們到達1,此時序列結束。例如,5的collat​​z序列是:{5,16,8,4,2,1}(因爲16 = 3 * 5 + 1,8 = 16/2,4 = 8/2,...)

我想寫一個函數(「maxCollat​​zUnder」),當它傳遞一個整數「m」時,返回具有最長Collat​​z序列(即最大Collat​​z數)的整數(小於或等於m) 。例如,maxCollat​​z 20(即,下面的哪個整數(包括)20具有最長的拼貼序列?)應該返回19(數字19具有長度爲21的Collat​​z序列:[19,58,29,88,44,22, 11,34,17,52,26,13,40,20,10,5,16,8,4,2,1])。

在下面的代碼中,「collat​​z」和「collat​​zHelper」函數編譯並正確運行。我在使用「maxCollat​​zUnder」功能時遇到了問題。該函數旨在(1)爲1到m範圍內的每個整數x(其中m是函數參數)創建一個2元組(x,y)的列表,其中y表示整數x的Collat​​z數,然後II)瀏覽列表中爲最高在Collat​​z數(即,y),並返回其相關的整數(即X)

maxCollatzUnder n = foldl(\acc (i,j) -> if j > acc then i else acc) 0 
    (zip [1..n] (map collatzLength [1..n])) 
    where collatzLength n = length . collatz $ n 

collatz n = map truncate $ collatzHelper n 

collatzHelper 0 = [0] 
collatzHelper 1 = [1] 
collatzHelper n 
    | (truncate n) `mod` 2 == 0 = [n] ++ collatzHelper (n/2) 
    | otherwise = [n] ++ collatzHelper (3*n+1) 

我收到以下錯誤,當我(嘗試)編制。

*Main> :l PE14Collatz.hs 
[1 of 1] Compiling Main    (PE14Collatz.hs, interpreted) 

PE14Collatz.hs:7:89: 
    No instance for (RealFrac Int) 
     arising from a use of `collatzLength' 
    In the first argument of `map', namely `collatzLength' 
    In the second argument of `zip', namely 
     `(map collatzLength [1 .. n])' 
    In the third argument of `foldl', namely 
     `(zip [1 .. n] (map collatzLength [1 .. n]))' 
Failed, modules loaded: none. 

有什麼奇怪的是,代碼編譯,如果我改變「maxCollat​​zUnder」下面的代碼(見下文)運行正常。唯一的變化是,在下面的版本中,摺疊函數返回「j」(即,最大Collat​​z數)而不是「i」(即,產生最大Collat​​z數的整數)。

maxCollatzUnder n = foldl(\acc (i,j) -> if j > acc then j else acc) 0 
    (zip [1..n] (map collatzLength [1..n])) 
    where collatzLength n = length . collatz $ n 

對更高效/優雅的方法的建議是受歡迎的,儘管我仍然有興趣瞭解這個錯誤的原因。

+0

你認爲這些函數的類型是什麼?例如,「collat​​z」的類型應該是什麼? – bheklilr 2014-10-02 02:16:52

回答

6

因爲你使用的truncate(的RealFrac的方法)和/(的Fractional的方法中,RealFrac超類)的,哈斯克爾推斷出以下兩種類型簽名的最後兩個功能:

collatz :: (RealFrac a, Integral b) => a -> [b] 
collatzHelper :: RealFrac a => a -> [a] 

哈斯克爾然後嘗試推算的maxCollatzUnder類型,其思維過程是這樣的:

  • 「在collatzLength n = length . collatz $ n ,我們通過ncollatz,所以collatzLength的參數必須是RealFrac。「

  • 「因此,在map collatzLength [1..n][1..n]必須是RealFrac值的列表。「

  • 」因此,在map collatzLength [1..n]n必須是RealFrac類型。「

  • 」。因此,在zip [1..n]n(其是相同n)必須是RealFrac式等[1..n]是一個的RealFrac名單。」

  • 「因此,在(\acc (i,j) -> if j > acc then i else acc)i必須是RealFrac。」

  • 「由於上述的λ可以返回iacc,它們必須是相同的類型」

  • 「因爲j正在相比accj必須是相同的類型acc - 並且因此相同類型iRealFrac。「

  • 」但WAIT - jcollatzLength的返回值,這是length一個調用的返回值,因此它必須是一個IntInt不在RealFrac

  • 」錯誤!錯誤!」

我現在得走了(編譯驚天動地不喜歡我放棄自己的祕密),但最短的解決方法是不使用truncate/,只是使用div的(地板),整數

+0

非常感謝您花時間解釋!您的解釋非常有意義(並且使用「股利「,而不是」截斷「和」/「的組合,確實工作!)。我會投票,但我沒有 – iceman 2014-10-02 03:31:32

+0

必要的帖子數量.... – iceman 2014-10-02 03:31:59