2015-03-13 27 views
3

为什么以下尝试在列表理解中模式匹配不起作用?表达式/列表解析中的模式匹配

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

的数据类型:

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

在术语原子的取代算法(采第一匹配取代如果任何和忽略其余部分):

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

一些测试数据:

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

运行示例结果如下:

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

这是所期望的行为,和

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

这是不。

Strangley明确的匹配工作的:

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

进料与所述测试数据导致:

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

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

我错过了什么?

+3

为了避免掉入这个错误在将来,我建议打开GHC的警告与'-Wall':这将指出'x'被绑定两次(内部'x'对外部阴影有影响)。 – chi 2015-03-13 10:59:06

回答

8

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

你试图做这样的事情:

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

但是,这是因为重复变量的错误。假如我们把第二c到内表达,它编译,但它仍打算不起作用:

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

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

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

subs :: [(Term a, Term a)] -> Term a -> Term a 
subs subList term = case term of 
    [email protected](Atom x)  -> let substitutions = 
           [ s | [email protected](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) 
+0

非常感谢你......如果我理解正确,在任何情况下'a'都是'Eq'的一个实例? – jules 2015-03-13 10:41:10

+2

@jules yes。为什么我们没有在模式中进行平等测试的一个原因是因为并非所有类型都是“Eq”的实例。我想它仍然可以作为语法糖来实现,但没有人真的认为它值得这样麻烦。 – 2015-03-13 10:44:54