我想要一个函数,它接受来自 Eq 的 a 列表和来自 Int 的 b 列表并返回 a 列表。我认为它应该是这样的:multiIndex :: (Eq a, Int b) => [a] -> [b] -> [a]但我收到以下错误消息:
Expected kind ‘* -> Constraint’, but ‘Int’ has kind ‘*’
In the type signature:
multiIndex :: (Eq a, Int b) => [a] -> [b] -> [a] typecheck
Run Code Online (Sandbox Code Playgroud)
整个功能将是:
multiIndex :: (Eq a, Int b) => [a] -> [b] -> [a]
multiIndex [] _ = []
multiIndex _ [] = []
multiIndex toBeExtracted values@(y:ys) = (toBeExtracted !! y) : (multiIndex toBeExtracted ys)
Run Code Online (Sandbox Code Playgroud)
我该如何解决这个问题,让它只接受一个 Int 列表作为第二个输入?
正如编译器所指出的,问题在于它Int是一个类型,而不是一个类型类。只需将您的签名重写为:
multiIndex :: (Eq a) => [a] -> [Int] -> [a]
Run Code Online (Sandbox Code Playgroud)
稍微扩展一下:
=>类型签名中箭头之前的所有内容都应该是对出现在主签名中的任何类型变量的“约束”。通常这意味着将类型限制为实现一个或多个类型类的类型。在Eq a你在你的类型的签名已经是一个典型的例子。它说“a我所指的必须是Eq类型类的一个实例”。
由于Int不是类型类,但实际上是类型,Int b因此在这里没有意义。你不是想说“b必须是Int类型类的一个实例”——你是想说这b实际上必须是特定类型,Int.
您实际上可以使用类型相等约束来实现这一点,它是这样写的:
(Eq a, b ~ Int)
Run Code Online (Sandbox Code Playgroud)
(请注意,这需要两种语言扩展中的任何一种,这是许多除非您需要否则不要使用它的一个很好的理由),并且说,以及“a必须是”的实例Eq,“b必须等于Int” . 在更高级的情况下,您需要执行此操作。但是,在大多数情况下,就像在这种情况下一样,完全没有必要,因为您可以简单地将类型变量替换为b您希望它等于的具体类型 - here Int。