Haskell:为什么我的最后一个实现对空列表有效?



我正在通过 Graham Hutton 的书"Programming in Haskell"中的练习,作为一项练习的一部分,我重新实现了 Haskell 的last函数,如下所示:

lasst xs = drop (length xs - 1) xs

现在这适用于非空列表:

> lasst [1,2,3,4,5]
[5]

但是,令我惊讶的是,对于空列表,它返回一个空列表:

> lasst []
[]

我对此感到惊讶,因为我希望(length []) - 1被评估为-1,随后对要抛出的drop -1 []进行评估。

为什么我的实现为空列表返回空列表,而不是引发异常?

Haskell报告'10指定了标准的前奏曲。在本节中,我们将看到:

drop                   :: Int -> [a] -> [a]  
drop n xs     |n <= 0=  xs  
drop _ []              =  []  
drop n (_:xs)          =  drop (n-1) xs

所以对于负n,它将返回整个列表。这对于drop的文档是有意义的:

drop n xs返回n元素后的后缀xs,如果n > length xs,则返回[]

因此,列表的前-1元素根本不是元素。

这在drop的例子之一中进一步介绍:

drop (-1) [1,2] == [1,2]

droptake是总函数:无论(总(参数是什么,它们总是返回一些东西而不会导致运行时错误。他们的定义使它使

take k xs ++ drop k xs == xs

每个k和(有限(xs都成立。注意k可以是负数,甚至大于xs的长度,以上还是有保证的。

起初可能会令人惊讶,但他们有以下行为。假设xs = [1,2,3].然后

k      take     drop
==========================
...
-2     []       [1,2,3]
-1     []       [1,2,3]
0      []       [1,2,3]
1      [1]      [2,3]
2      [1,2]    [3]
3      [1,2,3]  []
4      [1,2,3]  []
5      [1,2,3]  []
...

就个人而言,我不确定它们的整体性是否是一个好主意。对于负k或大于长度k,它们会导致运行时错误是有意义的。不过,这就是Haskell所做的。

(顺便注意,tail xsdrop 1 xsxs=[]时会有所不同,因为tail不是总的。

最新更新