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

jul*_*les 3 haskell list-comprehension pattern-matching

为什么以下尝试在列表推导中进行模式匹配不起作用?

示例:在术语数据类型中同时替换原子.

数据类型:

data Term a 
    = Atom a
    | Compound (Term a) (Term a)
    deriving Show
Run Code Online (Sandbox Code Playgroud)

原子的替换算法(选择第一个匹配的替换,如果有的话,忽略其余的):

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)
Run Code Online (Sandbox Code Playgroud)

一些测试数据:

subList = [((Atom 'a'), Compound (Atom 'b') (Atom 'c'))]
term1 = Atom 'a' 
term2 = Atom 'x' 
Run Code Online (Sandbox Code Playgroud)

运行该示例会导致:

>: subs subList term1
Compound (Atom 'b') (Atom 'c')
Run Code Online (Sandbox Code Playgroud)

这是期望的行为,和

>: subs subList term2
Compound (Atom 'b') (Atom 'c')
Run Code Online (Sandbox Code Playgroud)

不是.

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)
Run Code Online (Sandbox Code Playgroud)

使用测试数据输入结果:

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

>: subs''' subList term1 要么 >: subs''' subList term2
Atom 'x'

我错过了什么?

And*_*ács 8

Haskell具有线性模式,这意味着模式中不得有重复的变量.此外,内部表达式中的模式变量会影响外部变量,而不是建立相同变量的相等性.

你正试图做这样的事情:

charEq :: Char -> Char -> Bool
charEq c c = True
charEq _ _ = False
Run Code Online (Sandbox Code Playgroud)

但由于重复变量,这是一个错误.如果我们将第二个移动c到内部表达式,它会编译,但它仍然不能按预期工作:

charEq :: Char -> Char -> Bool
charEq c d = case d of
  c -> True
  _ -> False
Run Code Online (Sandbox Code Playgroud)

这里的内部c只是一个影响外部的新变量c,所以charEq总是返回True.

如果我们想检查相等性,我们必须==明确使用:

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)
Run Code Online (Sandbox Code Playgroud)

  • @jules是的.我们没有在模式中进行相等测试的一个原因是因为并非所有类型都是`Eq`的实例.我想它仍然可以作为语法糖实现,但没有人真的认为值得麻烦. (2认同)