[英]Passing a non-empty list to a function
I have written this small function to retrieve the tail of a list: 我写了这个小函数来检索列表的尾部:
let getTail l = if length l > 0 then tail l else "empty list"
Passing []
to getTail
returns empty list
but passing [1,2,3]
gives the following error: 传递[]
到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]
I can't understand what that error means. 我无法理解那个错误意味着什么。 What is the problem? 问题是什么? Using GHCi 7.0.4 使用GHCi 7.0.4
Let's think about the type of your getTail
function. 让我们考虑一下getTail
函数的类型。 Initially, we can imagine l
to be any list. 最初,我们可以想象l
是任何列表。 The return type, however, has to be a String
because you sometimes return "empty list"
. 但是,返回类型必须是String
因为有时会返回"empty list"
。 Since that's part of an if statement where you might also return tail l
, it means l
has to be a String
. 由于这是if语句的一部分,你也可能返回tail l
,这意味着l
必须是一个String
。
So your getTail
function has type String -> String
. 所以你的getTail
函数有String -> String
类型。
When you call getTail
with [1,2,3]
, it expects a String
, which is just a [Char]
. 当你用[1,2,3]
调用getTail
时,它需要一个String
,它只是一个[Char]
。 Remember that numeric literals are overloaded: [1,2,3]
is equivalent to calling [fromInteger 1, fromInteger 2, fromInteger 3]
. 请记住,数字文字是重载的: [1,2,3]
相当于调用[fromInteger 1, fromInteger 2, fromInteger 3]
。 So, given this list, Haskell is trying to get a number from a Char
. 因此,鉴于此列表,Haskell正试图从Char
获取一个数字。 Since Char
s are not part of the Num
class, this fails, giving you your error. 由于Char
不属于Num
类,因此会失败,从而导致错误。
A good solution would be to return a Maybe
type and give Nothing
for the error rather than returning "empty list"
. 一个好的解决方案是返回一个Maybe
类型并为错误提供Nothing
而不是返回"empty list"
。 So rewrite your function as: 所以重写你的功能:
let getTail l = if length l > 0 then Just (tail l) else Nothing
Now its type is [a] -> Maybe [a]
. 现在它的类型是[a] -> Maybe [a]
。 Using this will force anybody using your function to check whether getTail
succeeded before being able to use the result. 使用此方法将强制任何使用您的函数的人在能够使用结果之前检查getTail
是否成功。
Another option is to return []
in place of "empty list". 另一种选择是返回[]
代替“空列表”。 In this case, your getTail
function will work exactly like drop 1
. 在这种情况下, getTail
函数的工作方式与drop 1
完全相同。
Prelude> let getTail l = if length l > 0 then tail l else "empty list"
You didn't give getTail
a type signature, so one is inferred. 你没有给getTail
一个类型签名,所以推断出一个。
Prelude> :t getTail
getTail :: [Char] -> [Char]
:t
gives you the type of anything in GHCi. :t
给出GHCi中任何类型的东西。 This is extremely useful. 这非常有用。 Type signatures say a lot about a function in Haskell. 类型签名说明了很多关于Haskell中的函数。
This is probably not what you meant. 这可能不是你的意思。 Why does it only work on [Char]
, (or equivalently, String
), and not on any list? 为什么它只能在[Char]
,(或等效的String
)上工作,而不能在任何列表上工作?
Here's why: 原因如下:
A function can only have one return type. 一个函数只能有一个返回类型。 Since you return "empty list"
when the list is empty, the return type must be String
. 由于在列表为空时返回"empty list"
,因此返回类型必须为String
。 It just so happens that the return type of tail xs
where xs
is a [Char]
is also a String
, which is why you don't get an error when you first define the function. tail xs
, xs
为[Char]
的tail xs
的返回类型也是一个String
,这就是为什么在第一次定义函数时没有出错的原因。 Therefore your function as it is must be [Char] -> [Char]
. 因此,您的功能必须是[Char] -> [Char]
。
You're trying to call it with the argument [1, 2, 3]
, which has a type of Num a => a
. 你试图用参数[1, 2, 3]
来调用它,它的类型为Num a => a
。 GHC is telling you "A Char
doesn't have an instance of Num", or "I can't turn a number into a Char." GHC告诉你“A Char
没有Num的实例”,或者“我不能把数字变成Char。” This involves typeclasses—if you don't understand those yet, it doesn't matter, because you would still get an error of you tried getTail ([1, 2, 3] :: [Int])
. 这涉及类型类 - 如果你还不理解那些,那也没关系,因为你仍然会得到你试过getTail ([1, 2, 3] :: [Int])
。 You're trying to pass a list of Int
s to a function that takes a list of Char
s. 您正在尝试将Int
列表传递给一个获取Char
列表的函数。
I would recommend reading through LYAH to understand the Haskell type system. 我建议通过LYAH阅读以了解Haskell类型系统。
Should be rather []
instead of "empty list"
(You are mixing types) 应该是[]
而不是"empty list"
(你是混合类型)
Prelude> let getTail l = if length l > 0 then tail l else []
Prelude> getTail [1, 2, 3]
[2,3]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.