2011-08-21 188 views
1
chainQuery :: (Enum a, Integral a, Ord b) => a -> b -> [c] 
chainQuery n min = map length $ filter beatingLength $ map chain [1..n] 
    where 
    beatingLength :: [a] -> Bool 
    beatingLength xs = length xs > min 
    chain :: (Integral a) => a -> [a] 
    chain n 
     | n <= 1 = [n] 
     | even n = n:(chain $ div n 2) 
     | otherwise = n:(chain $ n * 3 + 1) 
  1. 在上述爲什麼不GHC能夠推導出的「C」是一個Int通過查看長度類型定義的代碼示例?GHC不decucing的方式我想它想:-(

  2. 爲什麼GHC需要了解「b」什麼比它是一個奧德其他?

  3. 有沒有寫這個功能更好的辦法?

+3

錘說,GHC是說「此用戶不演繹,我想他或她:-(方式」或許應該是這樣的錯誤消息。 –

+0

fromIntegral允許我有更通用的類型,所以這就是我最終使用的。 –

回答

8
  1. GHC能夠推斷出[Int]作爲函數的結果類型。問題是你在你的類型簽名中聲稱它應該是更多多態,結果可能是任何類型的列表,因爲返回值來自map length,所以它必須有類型[Int]。當它說Could not deduce (c ~ Int)時,這是GHC抱怨的。

  2. 您在比較minlength xs。大於號運算符的類型爲(>) :: (Ord a) => a -> a -> Bool,這意味着雙方必須是相同的類型。 length xs的類型爲Int,所以這也迫使minInt

  3. 也許吧。例如,您可以在執行過濾之前映射長度。這樣可以輕鬆使用操作員部分而不是您的beatingLength功能。您也可以移動圓括號以保存使用$以使代碼更簡潔。

    chainQuery n min = filter (> min) $ map (length . chain) [1..n] 
        where chain n | n <= 1 = [1] 
            | even n = n : chain (n `div` 2) 
            | otherwise = n : chain (3*n + 1) 
    

僅供參考,以解決一個問題像這樣的刪除您的簽名類型,看看什麼類型是GHCI推斷使用:t命令的最簡單方法。在這種情況下,推斷出的類型是

*Main> :t chainQuery 
chainQuery :: Integral a => a -> Int -> [Int] 
+1

此外,這是一個偏好問題,但我會將變量名稱'min'更改爲不會影響預先存在定義的內容(' min'是'Ord'類中的一個函數) –

+0

@Thomas:的確,如果你用'-Wall'選項編譯,GHC會提出警告,這會啓用所有的警告,並且通常是一個好主意, HLint](http://community.haskell.org/~ndm/hlint/)儘早發現潛在問題。 – hammar