Haskell - 无法将预期类型'b'与实际类型'a'匹配

时间:2017-11-09 20:19:31

标签: haskell recursion

刚开始学习Haskell和 我试图实现一个max函数来递归地找到列表的最大值

max' :: (Num b) => [a] -> b
max' [] = 0
max' (x:xs)
    | x > max' xs = x
    | otherwise = max' xs

但是在尝试编译时遇到错误

  

无法将预期类型'b'与实际类型'a'匹配         'a'是绑定的刚性类型变量           类型签名:             马克斯' :: forall b a。 (Num b,Num a)=> [a] - > b           在implementationFunctions.hs:5:1-34         'b'是绑定的刚性类型变量           类型签名:             马克斯' :: forall b a。 (Num b,Num a)=> [a] - > b           在implementationFunctions.hs:5:1-34

任何人都可以帮我理解什么是错的 ?

2 个答案:

答案 0 :(得分:10)

[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函数可能最好被看作是一个非总函数:一个函数,并非每个输入都会产生输出。在这种情况下,空列表不会。

我们可以将其重写为错误:

Maybe b

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

然而,编写错误并不总是处理非总函数的好方法,因为在类型签名中看不到函数是非整数的。另一个要做的就是使用 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]

答案 1 :(得分:1)

你的函数会获取一些东西并返回其中一个东西。但是函数的类型签名表示它需要一个b的列表,并返回一个完全不同的东西max' :: (Num a) => [a] -> a 。这困扰了编译器。它无法将声明的类型签名与实际实现(即“类型检查”)进行协调。

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

newlist = [100 if x == 0 else x for x in listzero]