从列表中删除第n个元素。

6
我自学 Haskell 已经有一个月左右了,今天我在阅读第 16 题的解答时想到了一个问题。
以下是链接:http://www.haskell.org/haskellwiki/99_questions/Solutions/16 基本上,这个问题要求编写一个函数,从列表中删除每个第 N 个元素。例如, *Main> dropEvery "abcdefghik" 3 "abdeghk" 链接中的第一个解决方案为:
dropEvery :: [a] -> Int -> [a]
dropEvery [] _ = []
dropEvery (x:xs) n = dropEvery' (x:xs) n 1 
  where
       dropEvery' (x:xs) n i = (if (n `divides` i) then [] else [x])++ (dropEvery' xs n (i+1))
       dropEvery' [] _ _ = []
       divides x y = y `mod` x == 0

我的问题是为什么dropEvery定义了空列表的情况,而dropEvery'可以处理空列表? 我认为可以简单地消除dropEvery [] _ = [],并将其他句子稍微修改如下,就可以完全与上面的代码相同,并且看起来更短。
dropEvery :: [a] -> Int -> [a]
dropEvery xs n = dropEvery' xs n 1 
  where
       dropEvery' (x:xs) n i = (if (n `divides` i) then [] else [x])++ (dropEvery' xs n (i+1))
       dropEvery' [] _ _ = []
       divides x y = y `mod` x == 0

可以有人帮我弄清楚这个吗?

1
请注意,此函数的参数顺序是“错误”的;像这样的函数通常是 Int -> [a] -> [a],在管道情况下通常更有用。为什么在该示例中将其放置在另一侧,我不知道。 - leftaroundabout
1个回答

7

我认为它们是相同的,作者可以像你建议的那样简化代码。出于好奇,我使用QuickCheck尝试了两个版本,它们似乎是相同的。


import Test.QuickCheck

dropEvery :: [a] -> Int -> [a]
dropEvery [] _ = []
dropEvery (x:xs) n = dropEvery' (x:xs) n 1 
  where
       dropEvery' (x:xs) n i = (if (n `divides` i) then [] else [x])++ (dropEvery' xs n (i+1))
       dropEvery' [] _ _ = []
       divides x y = y `mod` x == 0

dropEvery2 :: [a] -> Int -> [a]
dropEvery2 xs n = dropEvery' xs n 1 
  where
       dropEvery' (x:xs) n i = (if (n `divides` i) then [] else [x])++ (dropEvery' xs n (i+1))
       dropEvery' [] _ _ = []
       divides x y = y `mod` x == 0

theyAreSame xs n = (dropEvery xs n) == (dropEvery2 xs n)
propTheyAreSame xs n = n > 0 ==> theyAreSame xs n

在ghci中,您可以执行以下操作:
*Main> quickCheck propTheyAreSame 
+++ OK, passed 100 tests.

我也手动测试了一些边界情况。
*Main> dropEvery [] 0
[]
*Main> dropEvery2 [] 0
[]
*Main> dropEvery [] undefined
[]
*Main> dropEvery2 [] undefined
[]

所以它们似乎是相同的。

因此,我们的学习成果:

  1. Quickcheck非常适合这种类型的事情
  2. 不要低估你自己。 :)

谢谢你的回答! 很高兴听到我的猜测是正确的。我不知道Quickcheck。 我需要会使用GHC才能使用它吗? - Tengu
@Tengu 你不用 GHC 吗?你也可以使用 runghcghci,但我相信 QuickCheck 也可以在完全不同的编译器上工作。你可以搜索安装指南,但由于它是一个非常常见的库,所以安装应该非常容易。 - Tarrasch
我上个月刚开始学Haskell,之前从未使用过GHC编译器。(实际上,即使我的计算机科学专业朋友已经多次为我解释,“编译器”是什么意思我仍然不知道哈哈)我会查阅一下QuickCheck,但我可能还没有准备好处理那些东西。谢谢你的回答! - Tengu
1
@Tengu 好的,没问题。请以您觉得舒适的步伐学习,随着时间的推移,您的知识将得到完善,并且您会自然而然地探索更多的编程领域。另外,如果您发现我的回答有用,请考虑接受它。 - Tarrasch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接