Haskell 哈斯凯尔';t匹配预期类型‘;b&x2019;实际类型为‘;a’;

Haskell 哈斯凯尔';t匹配预期类型‘;b&x2019;实际类型为‘;a’;,haskell,recursion,Haskell,Recursion,刚开始学习Haskell和 我正在尝试实现一个max函数来递归地查找列表的max max' :: (Num b) => [a] -> b max' [] = 0 max' (x:xs) | x > max' xs = x | otherwise = max' xs 但是我在尝试编译时遇到了错误 无法将预期类型“b”与实际类型“a”匹配 “a”是一个刚性类型变量,由 以下项的类型签名: max':对于所有b a。(数字b,数字a)=>[a]->b 在执行功能时。

刚开始学习Haskell和 我正在尝试实现一个max函数来递归地查找列表的max

max' :: (Num b) => [a] -> b
max' [] = 0
max' (x:xs)
    | x > max' xs = x
    | otherwise = max' xs
但是我在尝试编译时遇到了错误

无法将预期类型“b”与实际类型“a”匹配 “a”是一个刚性类型变量,由 以下项的类型签名: max':对于所有b a。(数字b,数字a)=>[a]->b 在执行功能时。hs:5:1-34 “b”是一个刚性类型变量,由 以下项的类型签名: max':对于所有b a。(数字b,数字a)=>[a]->b 在执行功能时。hs:5:1-34

有人能帮我理解出了什么问题吗

max'
将一个
[a]
作为输入(基于签名):一个
a
的列表。但是您返回a
b
。这意味着,您已经编写了这样一个命令:不管列表中元素的类型如何,我们都可以根据需要选择任何类型的
b
,只要它是
Num b
。但这毫无意义。如果我们输入一个字符串列表,我们当然可以计算“最大字符串”(按字典顺序),但我们不能将其作为
Num
返回

另一个问题是使用
(>)::orda=>a->a->Bool
函数(作为保护)。但是您没有在函数签名中指定输入元素的类型必须是
Ord
typeclass的实例。所以你不能比较这些元素

最小的解决方案是将输入类型也限制为
b

现在有三种模式:(1)空列表,(2)singlton列表,以及(3)至少包含两个元素的列表

然而,编写错误并不总是处理非total函数的好方法,因为在类型签名中看不到函数是非total的。另一种方法是使用
或者b
作为返回类型。如果没有最大值,这将是一个
,如果有一个最大值,这将是一个
仅x

max' :: Ord b => [b] -> Maybe b
max' [] = Nothing
max' [x] = Just x
max' (x:xs@(_:_))
    | y <- max' xs = max x y
    | otherwise = Nothing

您的函数获取某物列表并返回其中一个某物。但是函数的类型签名表示它接受一个事物列表
[a]
,并返回一个完全不同的事物
b
。这使编译器感到困惑。它无法使声明的类型签名与实际实现相一致(也称为“类型检查”)

要解决此问题,请使类型签名与实现匹配:

max' :: (Num a) => [a] -> a 

我想你这样做是为了练习你的技能,但如果你不知道,这已经由函数实现了。是的,我知道,这只是为了练习。当你删除
0
,最好也删除残留的
Num
约束。@amalloy:正确。我没有考虑过这一点。谢谢你的反馈。
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)
max' :: (Num a) => [a] -> a