意外的模式匹配行为

时间:2013-09-14 19:02:42

标签: haskell

这是我的代码的简化版本:

data Exp = Var String

test :: Exp -> String -> Bool
test e vIn = case e of
                  Var vIn -> True
                  _       -> False

当我运行时:

test (Var "X") "Y"

我得到了真,这很奇怪,因为它需要匹配(Var vIn)和(Var s),s~ = vIn。

任何人都可以解释发生了什么,并建议一种解决方法吗?

2 个答案:

答案 0 :(得分:8)

Haskell不允许匹配模式中的变量,因为这需要这些变量的类型是Eq的实例。例如,这不起作用

isEqual :: Int -> Int -> Bool
isEqual a a = True
isEqual _ _ = False

它给出错误:

Conflicting definitions for `a'
...
In an equation for `isEqual

如果Haskell不允许这样的事情,为什么你的例子编译呢?您的代码中发生的事情是vIn语句中的case变量阴影 vIn变量绑定在等式中进行测试。如果使用-Wall标志进行编译,编译器也会对此发出警告:

code.hs:7:18: Warning:
This binding for `vIn' shadows the existing binding
  bound at code.hs:6:8

这意味着两个 vIn变量不相等,只有内部变量可见,因为它会影响外部变量。

要修复代码,您必须明确地将函数参数与案例中匹配的vIn值进行比较:

data Exp = Var String

test :: Exp -> String -> Bool
test e x = case e of
         Var vIn -> vIn == x -- Explicitly compare vIn to x
         _       -> False

或者只是在Var等式的test上使用警卫和模式匹配,如果这是一个选项:

data Exp = Var String

test :: Exp -> String -> Bool
test (Var a) vIn
  | a == vIn = ... {- Code for the case that vIn == a -}
  | otherwise = False

答案 1 :(得分:4)

匹配中的vIn正在隐藏vIn函数参数,绑定总是成功。您可以绑定到一个新变量并使用模式保护来检查值是否相等:

test e vIn = case e of
                  Var v | v == vIn -> True
                  _       -> False

或者,您可以直接与Var匹配,而不是使用case

test (Var v) vIn = v == vInt