为什么我得到一个无法推断(Ord a)错误?

foF*_*Fox 8 haskell

我试图找到具有最小元素总和的列表:

shortest :: (Num a) => [[a]] -> [a]
shortest [] = []
shortest (x:xs) = if sum x < sum (shortest xs) then x else shortest xs
Run Code Online (Sandbox Code Playgroud)

这给了我以下错误:

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
Run Code Online (Sandbox Code Playgroud)

为什么没有功能类型检查?

Has*_*ant 16

此代码涉及两个类型类:NumOrd.请注意,类型可以是成员Num而不是Ord,反之亦然.

类型sumNum a => [a] -> a输入元素shortest需要成为的成员Num.您还在代码中执行以下操作:

sum x < sum (shortest xs)
Run Code Online (Sandbox Code Playgroud)

这意味着您<as 上使用运算符,但在您的类型签名中,您并不要求as是其实例,Ord它定义<:

class Eq a => Ord a where
  compare :: a -> a -> Ordering
  (<) :: a -> a -> Bool
  ...
Run Code Online (Sandbox Code Playgroud)

因此,您需要将该要求添加到您的类型签名:

shortest :: (Ord a, Num a) => [[a]] -> [a]
Run Code Online (Sandbox Code Playgroud)

或者你可以省略类型签名.

  • 诊断此类问题并同时了解类型和类型类的更多信息的一种方法是暂时删除类型签名,将模块加载到GHCi中,然后输入":t shortest"以查看编译器的类型分配给它.同样,如果您遗漏了类型签名,请尝试添加它以查看您的函数是否具有您期望的类型签名.我用这种技术学到了很多东西. (5认同)

jto*_*bin 5

Num不包括Ord,所以你在类型签名中缺少Ord约束a.它应该是

shortest :: (Num a, Ord a) => [[a]] -> [a]
Run Code Online (Sandbox Code Playgroud)

您可以删除类型签名,GHC将为您推断.