简体   繁体   English

将非空列表传递给函数

[英]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 xsxs[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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM