简体   繁体   中英

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:

<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

Let's think about the type of your getTail function. Initially, we can imagine l to be any list. The return type, however, has to be a String because you sometimes return "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 .

So your getTail function has type String -> String .

When you call getTail with [1,2,3] , it expects a String , which is just a [Char] . Remember that numeric literals are overloaded: [1,2,3] is equivalent to calling [fromInteger 1, fromInteger 2, fromInteger 3] . So, given this list, Haskell is trying to get a number from a Char . Since Char s are not part of the Num class, this fails, giving you your error.

A good solution would be to return a Maybe type and give Nothing for the error rather than returning "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] . Using this will force anybody using your function to check whether getTail succeeded before being able to use the result.

Another option is to return [] in place of "empty list". In this case, your getTail function will work exactly like 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.

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

:t gives you the type of anything in GHCi. This is extremely useful. Type signatures say a lot about a function in Haskell.

This is probably not what you meant. Why does it only work on [Char] , (or equivalently, String ), and not on any list?

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 . 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. Therefore your function as it is must be [Char] -> [Char] .

You're trying to call it with the argument [1, 2, 3] , which has a type of 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." 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]) . You're trying to pass a list of Int s to a function that takes a list of Char s.

I would recommend reading through LYAH to understand the Haskell type system.

Should be rather [] instead of "empty list" (You are mixing types)

Prelude> let getTail l = if length l > 0 then tail l else []
Prelude> getTail [1, 2, 3]
[2,3]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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