【问题标题】:Haskell: Why does my implementation of last work for an empty list?Haskell:为什么我的 last 实现适用于空列表?
【发布时间】:2020-04-27 12:41:57
【问题描述】:

我正在完成 Graham Hutton 的“Haskell 编程”一书中的练习,作为练习的一部分,我重新实现了 Haskell 的 last 函数,如下所示:

lasst xs = drop (length xs - 1) xs

现在这对非空列表很有效:

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

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

> lasst []
[]

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

为什么我的实现会为空列表返回一个空列表,而不是抛出异常?

【问题讨论】:

  • 你应该为-1使用括号,所以drop (-1) [],否则你执行drop - 1 [],这没有多大意义。
  • 如果索引为负数,则不删除任何元素。这也包含在 Haskell 报告中。
  • 谢谢@willem-van-onsem。事实上,我看到来自drop -1 [] 的异常是由于缺少括号。当我添加它们时,drop (-1) [] 根据规范返回[]
  • 这也不例外。
  • BTW drop (length xs - 1) xs 效率极低:它会遍历列表一次以获取其长度;然后再次删除前缀。更好的是直接使用模式匹配编码lasst。 (然后您可以对其进行编码以在空列表上引发异常。)

标签: haskell


【解决方案1】:

Haskell report '10 指定standard Prelude。在本节中,我们看到:

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

所以对于否定的n,它将返回整个列表。这对于documentation of drop 来说是有道理的:

drop n xs第一个n 元素 之后返回xs 的后缀,如果n &gt; length xs 则返回[]

所以列表的第一个 -1 元素根本不是元素。

drop 的示例之一进一步介绍了这一点:

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

【讨论】:

    【解决方案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不是总数。)

    【讨论】:

    • 你为什么用“有限”来限定这个?这不也适用于无限列表吗?
    • @JosephSible-ReinstateMonica 是的,如果 == 是指称等价。相反,如果这是 Haskell 相等,我们没有 [0..] == [0..] 评估为 True。 (最初,我确实忽略了它,然后我变得更加迂腐,并添加它只是为了安全。)
    • 是的,但是如果你的意思是 Haskell 相等,那么你还需要一堆其他的例外,比如其中一个列表中的undefined,或者带有病态的Eq 实例的类型,比如Double
    • @JosephSible-ReinstateMonica 上面我需要全部参数,所以undefined 不在了。还应该确实假设一个自反的Eq(我假设Eq Double 不是因为NaN)。列举所有确切的假设很麻烦:-/
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-23
    • 2015-02-07
    • 1970-01-01
    • 2021-02-28
    • 1970-01-01
    • 1970-01-01
    • 2020-01-04
    相关资源
    最近更新 更多