我写了这个小函数来检索列表的尾部:
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
答案 0 :(得分:7)
让我们考虑一下getTail
函数的类型。最初,我们可以将l
想象成任何列表。但是,返回类型必须是String
,因为有时您会返回"empty list"
。由于这是if语句的一部分,您可能还会返回tail l
,这意味着l
必须为String
。
因此,您的getTail
函数的类型为String -> String
。
当您使用getTail
致电[1,2,3]
时,它需要String
,这只是[Char]
。请记住,数字文字已超载:[1,2,3]
相当于调用[fromInteger 1, fromInteger 2, fromInteger 3]
。所以,根据这个列表,Haskell试图从Char
获得一个数字。由于Char
不属于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
完全相同。
答案 1 :(得分: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
xs
的返回类型[Char]
也是String
,这就是您在第一次定义时没有收到错误的原因功能。因此,您的功能必须是[Char] -> [Char]
。
您尝试使用[1, 2, 3]
参数调用它,其类型为Num a => a
。 GHC告诉你“A Char
没有Num的实例”,或者“我无法将数字变成Char。”这涉及类型类 - 如果你还不了解它们,那也没关系,因为你仍然会遇到错误的尝试getTail ([1, 2, 3] :: [Int])
。您正尝试将Int
列表传递给一个带有Char
列表的函数。
我建议阅读LYAH以了解Haskell类型系统。
答案 2 :(得分:1)
应该是[]
而不是"empty list"
(您正在混合类型)
Prelude> let getTail l = if length l > 0 then tail l else []
Prelude> getTail [1, 2, 3]
[2,3]