无法与实际类型'a'匹配预期类型'b'
刚开始学习Haskell和Im试图实现一个最大函数来递归地查找列表的最大值
max' :: (Num b) => [a] -> b
max' [] = 0
max' (x:xs)
| x > max' xs = x
| otherwise = max' xs
但在编译时遇到错误
无法与实际类型'a'匹配预期类型'b''a'是由类型签名绑定的刚性类型变量:max':: forall b a。 (数字b,数字a)=> [a] - > b在实现函数.hs:5:1-34'b'是一个刚性类型变量,其类型签名为:max':: forall b a。 (数字b,数字a)=> [a] - > b在实现函数.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
链接地址: http://www.djcxy.com/p/43437.html