将非空列表传递给函数

时间:2012-07-21 19:12:50

标签: haskell parameter-passing tail

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

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

3 个答案:

答案 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]