问题描述
dropEvery :: [a] -> Int -> [a]
dropEvery xs n = f xs n ++ dropEvery (drop n xs) n
where
f ys 0 = []
f ys 1 = []
f [] m = []
f (y:ys) n = y : (f ys (n-1))
我想让它更短一点,并且想知道是否有一种方法可以在模式匹配中使用“where 子句执行此操作,但不起作用,为什么?
f ys m = []
where
m <= 1 || ys == []
我怎样才能避免这种冗余?在模式匹配中使用“小于或等于”有什么好方法吗?
编辑:我用守卫试过这个
where
f ys m
| m <= 1 || null ys = []
| otherwise = (head ys) : (f (tail ys) (n-1))
解决方法
您可以与守卫一起工作:
dropEvery :: [a] -> Int -> [a]
dropEvery xs n = f xs n ++ dropEvery (drop n xs) n
where
f ys i | i <= 1 = []
f [] _ = []
f (y:ys) n = y : (f ys (n-1))
如果满足守卫中的条件,则该子句“触发”,因此在这种情况下将返回一个空列表[]
。
然而你会陷入无限循环,因为你写了 f xs n ++ dropEvery (n xs) n
但 drop 3 []
会返回 []
,因此它会继续调用 dropEvery
并带有一个空列表.
您可以使用递归,每次递减 n
直到达到 0
,然后我们进行两次跳跃,因此:
dropEvery :: Int -> [a] -> [a]
dropEvery n = go (n-1)
where go _ [] = []
go i (x:xs)
| i <= 0 = go (n-1) xs
| otherwise = x : go (i-1) xs
我们还可以使用 splitAt :: [a] -> ([a],[a])
和模式保护:
dropEvery n [] = []
dropEvery n ds
| (_:ys) <- sb = sa ++ dropEvery n ys
| otherwise = sa
where (sa,sb) = splitAt (n-1) ds