![](/img/trans.png)
[英]Haskell: Couldn't match expected type ‘(a, b0)’ with actual type ‘(a, b, h)’
[英]Haskell - Couldn't match expected type ‘b’ with actual type ‘a’
剛開始學習Haskell,我試圖實現一個max函數來遞歸地查找列表的最大值
max' :: (Num b) => [a] -> b
max' [] = 0
max' (x:xs)
| x > max' xs = x
| otherwise = max' xs
但在嘗試編譯時遇到錯誤
無法將預期類型'b'與實際類型'a'匹配'a''是由類型簽名綁定的剛性類型變量:max':: forall b a。 (Num b,Num a)=> [a] - > b at implementationFunctions.hs:5:1-34'b'是由類型簽名綁定的剛性類型變量:max':: forall b a。 (Num b,Num a)=> [a] - > b at implementationFunctions.hs:5:1-34
任何人都可以幫我理解什么是錯的?
max'
作為輸入(基於所述簽名)的[a]
一個列表a
第 但你回來了b
。 這意味着你已經寫了 - 無論列表中元素的類型如何 - 我們可以選擇任何類型b
作為我們想要的輸出,只要它是Num b
。 但這沒有意義。 如果我們輸入字符串列表,我們當然可以計算“最大字符串”(按字典順序),但我們不能將其作為Num
返回。
另一個問題是你使用(>) :: Ord a => a -> a -> Bool
函數(作為一個守護者)。 但是,您沒有在函數簽名中指定輸入元素的類型必須是Ord
類型類的實例。 所以你無法比較這些元素。
最小的修復是將輸入類型限制為b
:
max' :: (Ord b, Num b) => [b] -> b
max' [] = 0
max' (x:xs)
| x > max' xs = x
| otherwise = max' xs
話雖如此,如果我們提供一個空列表,返回0
沒有多大意義。 這將導致一個奇怪的事實,即max []
實際上大於max [-1]
:通常我們期望超集的最大值大於或等於集合的最大值。
因此, max'
函數可能最好被視為非總函數:不是每個輸入都會導致輸出的函數。 在這種情況下,空列表不會。
我們可以將其重寫為錯誤:
max' :: Ord b => [b] -> b
max' [] = error "Empty list"
max' [x] = x
max' (x:xs@(_:_))
| x > max' xs = x
| otherwise = max' xs
所以現在有三種模式:(1)空列表,(2)單元列表,以及(3)具有至少兩個元素的列表。
然而,編寫錯誤並不總是處理非總函數的好方法,因為在類型簽名中看不到函數是非總函數。 另一個想做的就是使用Maybe b
作為返回類型。 如果沒有最大值,這將是一個Nothing
,如果有一個,則為Just x
:
max' :: Ord b => [b] -> Maybe b
max' [] = Nothing
max' [x] = Just x
max' (x:xs@(_:_))
| y <- max' xs = max x y
| otherwise = Nothing
或更短:
max' :: Ord b => [b] -> Maybe b
max' [] = Nothing
max' [x] = Just x
max' (x:xs@(_:_)) = fmap (max x) (max' xs)
例如:
Prelude> max' []
Nothing
Prelude> max' [1,4,2,5]
Just 5
Prelude> max' [-3]
Just (-3)
你的函數會獲取一些東西並返回其中一個東西。 但是函數的類型簽名表明它需要一個東西[a]
的列表並返回一個完全不同的東西b
。 這困擾了編譯器。 它無法將聲明的類型簽名與實際實現(又稱“類型檢查”)進行協調。
要解決此問題,請使類型簽名與實現匹配:
max' :: (Num a) => [a] -> a
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.