在 Haskell 中有没有办法使用“<=”进行模式匹配?

Is there a way to use "<=" for pattern matching in Haskell?

我有以下代码,它删除列表中的第 n 个元素。

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 <b>| i <= 1</b> = []
        f [] _ = []
        f (y:ys) n = y : (f ys (n-1))

如果守卫中的条件得到满足,则该子句“触发”,因此在这种情况下将 return 一个空列表 []

但是你会陷入无限循环,因为你写 f xs n ++ <b>dropEvery (n xs) n</b> 但是drop 3 [] 将 return [],因此它将继续使用空列表调用 dropEvery

你可以利用递归,我们每次递减 n 直到它达到 0,然后我们进行两次跳跃,所以:

dropEvery :: Int -> [a] -> [a]
dropEvery n = go (n-1)
    where go _ [] = []
          go i (x:xs)
              | <b>i <= 0</b> = go (n-1) xs
              | otherwise = x : go (i-1) xs

我们还可以使用 splitAt :: [a] -> ([a], [a]) 模式守卫:

dropEvery n [] = []
dropEvery n ds
    | <b>(_:ys) <- sb</b> = sa ++ dropEvery n ys
    | otherwise = sa
    where (sa, sb) = splitAt (n-1) ds