简体   繁体   English

案例表达式/列表理解中的模式匹配

[英]Pattern matching in case expressions/list comprehensions

Why does the following attempt to pattern-match in a list comprehension not work? 为什么以下尝试在列表推导中进行模式匹配不起作用?

Example: simultaneous substitution of atoms in a term data type. 示例:在术语数据类型中同时替换原子。

The data type: 数据类型:

data Term a 
    = Atom a
    | Compound (Term a) (Term a)
    deriving Show

The substitution algorithm for atoms in terms (picks the first matching substitution if any and ignores the rest): 原子的替换算法(选择第一个匹配的替换,如果有的话,忽略其余的):

subs :: [(Term a, Term a)] -> Term a -> Term a
subs subList term = case term of 
    atom@(Atom x)       ->  let substitutions = 
                                [ s | s@(Atom x, _) <- subList ]
                            in  if null substitutions
                                then atom
                                else snd . head $ substitutions
    (Compound t1 t2)    -> Compound (subs subList t1) (subs subList t2)

Some test data: 一些测试数据:

subList = [((Atom 'a'), Compound (Atom 'b') (Atom 'c'))]
term1 = Atom 'a' 
term2 = Atom 'x' 

Running the example results in: 运行该示例会导致:

>: subs subList term1
Compound (Atom 'b') (Atom 'c')

which is the desired behaviour, and 这是期望的行为,和

>: subs subList term2
Compound (Atom 'b') (Atom 'c')

which is not. 不是。

Strangley explicit matching works: Strangley显式匹配工作:

subs'' :: [(Term Char, Term Char)] -> Term Char -> Term Char
subs'' subList term = case term of 
    atom@(Atom _)       ->  let substitutions = 
                            [ s | s@(Atom 'a', _) <- subList ]
                            in  if null substitutions
                                then atom
                                else snd . head $ substitutions
    (Compound t1 t2)    -> Compound (subs subList t1) (subs subList t2)

subs''' subList term = case term of 
     atom@(Atom _)       ->  let substitutions = 
                             [ s | s@(Atom 'x', _) <- subList ]
                             in  if null substitutions
                                 then atom
                                 else snd . head $ substitutions
     (Compound t1 t2)    -> Compound (subs subList t1) (subs subList t2)

feed with the test data result in: 使用测试数据输入结果:

>: subs'' subList term1 or >: subs'' subList term2 >: subs'' subList term1>: subs'' subList term2
Compound (Atom 'b') (Atom 'c')

>: subs''' subList term1 or >: subs''' subList term2 >: subs''' subList term1>: subs''' subList term2
Atom 'x'

What am I missing? 我错过了什么?

Haskell has linear patterns, meaning that there must be no repeated variables in patterns. Haskell具有线性模式,这意味着模式中不得有重复的变量。 Also, pattern variables in inner expressions shadow outer variables, instead of establishing equality of identical variables. 此外,内部表达式中的模式变量会影响外部变量,而不是建立相同变量的相等性。

You're trying to do something like this: 你正试图做这样的事情:

charEq :: Char -> Char -> Bool
charEq c c = True
charEq _ _ = False

But this is an error because of the repeated variables. 但由于重复变量,这是一个错误。 If we move the second c to an inner expression, it compiles, but it still doesn't work as intended: 如果我们将第二个c移动到内部表达式,它会编译,但它仍然不能按预期工作:

charEq :: Char -> Char -> Bool
charEq c d = case d of
  c -> True
  _ -> False

Here the inner c is just a new variable that shadows the outer c , so charEq always returns True . 这里的内部c只是一个charEq外部c的新变量,所以charEq总是返回True

If we'd like to check for equality we must use == explicitly: 如果我们要检查是否相等,我们必须明确地使用==

subs :: [(Term a, Term a)] -> Term a -> Term a
subs subList term = case term of 
    atom@(Atom x)       ->  let substitutions = 
                                [ s | s@(Atom x', _) <- subList, x == x' ]
                            in  if null substitutions
                                then atom
                                else snd . head $ substitutions
    (Compound t1 t2)    -> Compound (subs subList t1) (subs subList t2)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM