模式匹配可以用于列表成员吗?

Can Pattern Matching be used for list membership?

我知道我可以使用守卫来检查某个值是否出现在列表中,但我想知道 单独的模式匹配 是否也可以用于此。

-- Using guards
f :: [Int] -> Int
f xs
    | 42 `elem` xs = 42
    | otherwise = 0

-- Using pattern matching?
g :: [Int] -> Int
g (_:)*42:_ = 42  -- i.e. zero or more elements: we discard until 42, followed by whatever.
g _         = 0

简答:否
长答案:
模式递归定义如下:

pattern := variable
         | constant
         | C p1 p2... where C is a constructor and p1 p2... are patterns
         | variable@pattern

Can Pattern Matching be used for list membership?

仅通过递归地应用模式,例如

elem :: Eq a => a -> [a] -> Bool
elem x [] = False
elem x (y:ys) = x == y || elem x ys

所以 none 模式 []y:ys 自己检查列表成员。

但是与递归相结合,它们是有帮助的。

"Zero or more elements we discard until 42, followed by whatever."

没有。

此模式将仅匹配以 42 作为第二个元素的列表。 : 是列表构造函数,composes\decomposes 以独特的方式列出的东西,而不是连接,连接是 "to complex" 用于模式匹配。

是的。仅使用文字 Int 值;递归地。

-- Using pattern matching alone
g :: [Int] -> Int
g (42:_) = 42 
g []     = 0
g (_:r)  = g r

测试:

> g [1..50]
42

> g [1]
0

虽然模式中没有类似正则表达式的结构。我希望我们可以写类似

的东西
foo [...xs, 42, ...ys] = xs ++ ys
foo _ = []

但我们不能。

更新:根据@chi in the 的建议;使用 查看模式;

{-# LANGUAGE ViewPatterns #-}

g2 (break (== 42) -> (_,[])) = 0   -- 0,  if not found
g2 _ = 42                          -- 42, otherwise

我不确定它是否算作 "patterns alone",因为它使用 "regular" 标准函数 break。优点是,它不再只是文字。

你可以,在某种程度上,但它需要启用 GHC 扩展。

{-# LANGUAGE ViewPatterns -#}

g :: [Int] -> Int
g ((42 `elem`) -> True) = 42
g _         = 0

如果 f x 匹配 v.

,则 f -> v 形式的模式匹配参数 x