Haskell类型签名:lastButOne程序的类型签名问题

Haskell类型签名:lastButOne程序的类型签名问题,haskell,types,Haskell,Types,我正在阅读真实世界的Haskell,其中一个练习是构造一个函数lastButOne,它只返回列表中倒数第二个元素 到目前为止,我的代码是: lastButOne xs = if null xs || length xs == 1 then [] else if length xs == 2 then head xs else lastButOne (ta

我正在阅读真实世界的Haskell,其中一个练习是构造一个函数lastButOne,它只返回列表中倒数第二个元素

到目前为止,我的代码是:

lastButOne xs = if null xs || length xs == 1
                    then []
                else if length xs == 2
                    then head xs
                else lastButOne (tail xs)

我的问题: 输入应该是一个列表,如果它不是空的或长度为1,则返回一个空列表,在其他情况下,返回倒数第二个元素。然而,当我输入一个列表时,我得到了一个错误。当我输入二阶嵌套列表时,我没有得到任何错误

我怀疑类型签名有问题,当我调用类型签名时,它返回

lastButOne :: [[a]] -> [a].

但是我希望类型签名是
[a]->a
。我已经盯着这个函数看了一段时间,也浏览了其他帖子,但我似乎不明白为什么类型签名是
[[a]]->a
。任何提示都将不胜感激。

您可以通过在代码中添加
lastButOne::[a]->[a]
来明确声明函数的类型签名。然后,函数将期望xs是一个列表

但是我们会遇到另一个错误:函数的一个输出(
headxs
)实际上不是一个列表
[a]
,而是一个元素
a

如果添加签名
lastButOne::[A]>A
,则会弹出类似的错误消息,但这一次是因为
[]
不是
A
类型的元素


一个简单的解决方案可能是返回列表中倒数第二个元素,使用
[head xs]
作为输出。

您可以通过以下模式匹配来完成:

lastButOne :: [a] -> a
lastButOne []    = error "not elements"
lastButOne [x]   = x
lastButOne [x,_] = x
lastButOne (x:xs) = lastButOne xs

提示:当前的函数可以返回
[]
或输入列表的元素,因此它们必须具有相同的类型。(我怀疑这个练习并不打算让你去处理错误案例——而且我认为除了使用
也许
(你可能还没有学过)之外,没有更好的方法来处理它们。)哦,我看到了我的错误。当
length xs时,我一起返回
head xs
来修复它。您可以将其设置为运行时错误,但类型为
[a]>的函数可能更合适。“Short”列表返回
Nothing
;较长的列表返回的
仅为x
(其中
x
是列表中的适当值)。@trujello,如果列表为空,前奏中的
head
将引发运行时错误。人们不太喜欢它,但在你学会更好的技术之前,它是可以的。您可以说,例如,
错误“列表为空”
。作为一般的经验法则,如果您使用的是
头、尾、您应该考虑使用模式匹配——这些函数可以很容易地将程序错误地输入,当(穷尽)模式匹配永远不会出错时。相反,
length list==constant
从不崩溃,但通常效率很低,因为当只有第一个元素就足够时,它会扫描整个列表——同样,模式匹配是一种方法;你能澄清一下你在这里的意思吗,即模式匹配?@trujello,模式匹配是这种定义风格的名称,你为定义的函数给出了多个方程。第一个说明在给定一个空列表时要做什么,第二个说明在给定一个包含一个元素的列表时要做什么,依此类推。我不完全相信OP想要
lastButOne[x]=x
,而不是一个错误。(+1)