从列表中删除第n个元素

时间:2013-04-27 16:34:51

标签: haskell

我一直在教自己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 个答案:

答案 0 :(得分: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. 不要低估自己。 :)