意外的模式匹配行为

use*_*015 4 haskell

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

data Exp = Var String

test :: Exp -> String -> Bool
test e vIn = case e of
                  Var vIn -> True
                  _       -> False
Run Code Online (Sandbox Code Playgroud)

当我运行这个:

test (Var "X") "Y"
Run Code Online (Sandbox Code Playgroud)

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

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

ben*_*ofs 8

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

isEqual :: Int -> Int -> Bool
isEqual a a = True
isEqual _ _ = False
Run Code Online (Sandbox Code Playgroud)

它给出了错误:

Conflicting definitions for `a'
...
In an equation for `isEqual
Run Code Online (Sandbox Code Playgroud)

如果Haskell不允许这样的事情,为什么你的例子编译呢?什么发生在你的代码是,vIn在变量case声明阴影vIn公式测试中的约束变量.如果使用-Wall标志进行编译,编译器也会向您发出警告:

code.hs:7:18: Warning:
This binding for `vIn' shadows the existing binding
  bound at code.hs:6:8
Run Code Online (Sandbox Code Playgroud)

这意味着有两个 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
Run Code Online (Sandbox Code Playgroud)

或者只是Vartest等式中使用防护和模式匹配,如果这是一个选项:

data Exp = Var String

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