2012-10-21 75 views
8

我試圖找到這給了我下面的錯誤元素的總和最小:爲什麼我得到一個無法推斷(Ord a)錯誤?

shortest :: (Num a) => [[a]] -> [a] 
shortest [] = [] 
shortest (x:xs) = if sum x < sum (shortest xs) then x else shortest xs 

名單:

Could not deduce (Ord a) arising from a use of `<' 
from the context (Eq a) 
    bound by the type signature for shortest :: Eq a => [[a]] -> [a] 
    at code.hs:(8,1)-(9,71) 
Possible fix: 
    add (Ord a) to the context of 
    the type signature for shortest :: Eq a => [[a]] -> [a] 
In the expression: sum x < sum (shortest xs) 
In the expression: 
    if sum x < sum (shortest xs) then x else shortest xs 
In an equation for `shortest': 
    shortest (x : xs) 
     = if sum x < sum (shortest xs) then x else shortest xs 

爲什麼沒有函數類型檢測?

+0

「最短」並不是真正的正確名稱,是嗎? - 考慮在'Data.List'和'Data.Function'中使用'minimumBy(比較'\ sum)''的高階函數。 – leftaroundabout

+1

要理解這個問題,重要的是要知道並非所有數字都可以訂購。例如,考慮像「1 + 2i」這樣的複數;沒有規範它們的規範方法。 – dflemstr

+1

@leftaroundabout已經提出了一個使用庫函數的解決方案;但是如果你仍然想從頭開始寫作練習,除了解決類型簽名問題之外,還需要考慮'最短'[]'的值應該是什麼,換句話說,是什麼應該是遞歸的基礎(提示:通常不會爲空列表定義「最小」和「最大」)。 –

回答

15

此代碼涉及兩種類型類別:NumOrd。注意 ,類型可以是成員Num而不是Ord,反之亦然。

sum的類型是Num a => [a] -> a所以輸入元素shortest需要是Num的成員。您還做以下的代碼 :

sum x < sum (shortest xs) 

這意味着,你正在使用的運營商<a S,但在你的類型簽名你不要求a s內的Ord實例定義<

class Eq a => Ord a where 
    compare :: a -> a -> Ordering 
    (<) :: a -> a -> Bool 
    ... 

因此你需要這一要求添加到您的類型簽名:

shortest :: (Ord a, Num a) => [[a]] -> [a] 

或者您可以省略型號簽名。

+4

診斷此類問題的一種方法是,要同時瞭解類型和類型類的更多信息,請暫時刪除類型簽名,將模塊加載到GHCi中,然後輸入「:t最短」來查看類型編譯器分配給它。同樣,如果您遺漏了類型簽名,請嘗試添加它以查看您的函數是否具有您期望的類型簽名。我學到了很多使用這種技術。 – mhwombat

5

Num不包括Ord,所以你在類型簽名中缺少aOrd約束。它應該是

shortest :: (Num a, Ord a) => [[a]] -> [a] 

您可以刪除類型簽名,GHC會爲您推斷這一點。