2

我编写了这个小函数来检索列表的尾部:

let getTail l = if length l > 0 then tail l else "empty list"

传递[]getTail返回empty list但传递[1,2,3]给出以下错误:

<interactive>:1:14:
No instance for (Num Char)
  arising from the literal `3'
Possible fix: add an instance declaration for (Num Char)
In the expression: 3
In the first argument of `getTail', namely `[1, 2, 3]'
In the expression: getTail [1, 2, 3]

我不明白那个错误是什么意思。问题是什么?使用 GHCi 7.0.4

4

3 回答 3

7

让我们考虑一下您的getTail函数的类型。最初,我们可以想象l成为任何列表。但是,返回类型必须是 aString因为您有时会返回"empty list"。由于这是 if 语句的一部分,您也可以在其中 return tail l,这意味着l 必须String.

所以你的getTail函数有 type String -> String

当您调用getTailwith 时[1,2,3],它需要一个String,这只是一个[Char]。请记住,数字文字是重载的:[1,2,3]相当于调用[fromInteger 1, fromInteger 2, fromInteger 3]. 所以,给定这个列表,Haskell 试图从Char. 由于Chars 不是Num该类的一部分,因此这会失败,从而给您带来错误。

一个好的解决方案是返回一个Maybe类型并给出Nothing错误而不是返回"empty list"。所以将你的函数重写为:

let getTail l = if length l > 0 then Just (tail l) else Nothing

现在它的类型是[a] -> Maybe [a]. 使用它会强制任何使用你的函数的人getTail在能够使用结果之前检查是否成功。

另一种选择是返回[]代替“空列表”。在这种情况下,您的getTail函数将与drop 1.

于 2012-07-21T19:19:34.743 回答
2
Prelude> let getTail l = if length l > 0 then tail l else "empty list"

您没有给出getTail类型签名,因此推断出一个。

Prelude> :t getTail
getTail :: [Char] -> [Char]

:t为您提供 GHCi 中任何内容的类型。这是非常有用的。类型签名对 Haskell 中的函数有很多说明。

这可能不是你的意思。为什么它只适用于[Char], (或等效地 , String),而不适用于任何列表?

原因如下:

一个函数只能有一种返回类型。由于您"empty list"在列表为空时返回,因此返回类型必须为String. tail xs碰巧where xsis a的返回类型[Char]也是 a String,这就是为什么当你第一次定义函数时不会出错的原因。因此,您的功能必须是[Char] -> [Char].

你试图用参数来调用它[1, 2, 3],它的类型是Num a => a. GHC 告诉您“AChar没有 Num 的实例”,或者“我无法将数字转换为 Char”。这涉及到类型类——如果你还不理解这些,那没关系,因为你仍然会得到一个你尝试过的错误getTail ([1, 2, 3] :: [Int])。您正在尝试将 s 列表传递给接受Ints 列表的函数Char

我建议通读LYAH以了解 Haskell 类型系统。

于 2012-07-21T19:15:59.983 回答
1

应该而[]不是"empty list"(您正在混合类型)

Prelude> let getTail l = if length l > 0 then tail l else []
Prelude> getTail [1, 2, 3]
[2,3]
于 2012-07-21T19:18:19.797 回答