在`case~of`中没有修复一个值

时间:2016-08-08 08:51:25

标签: haskell case

我的情况:

在我的代码中,值xID似乎在case ~ of结构中是变量。

import Debug.Trace

data I = I
  { iID :: Int } deriving Show
data C = C
  { i :: I} deriving Show

x = I 0
aC2 = C (I 2)
aC3 = C (I 3)
aC5 = C (I 5)

xID = iID x

cConverter aC =
  trace ((show cIID) ++ (if cIID == xID then "==" else "/=") ++ (show xID) ++ " when " ++ (show x)) $
    "Point: " ++ pID
  where
    pID :: String
    pID =
      case cIID of
        xID -> trace ((show cIID) ++ (if cIID == xID then "==" else "/=") ++ (show xID) ++ " when " ++ (show x)) "X"
        _ -> show cIID
    cIID = iID . i $ aC
    -- xID = iID x

我的期望

我预计当我运行cConverter aC2时,我会"2",因为2中的aC2 = C (I 2)不等于0 x = I 0 1}}。

会发生什么

然而,当我运行cConvert aC2时,我遇到了奇怪的结果:

Main> cConverter aC2
"2/=0 when I {iID = 0}
Point: 2==2 when I {iID = 0}
X"

为什么我会"X"代替"2"? 更确切地说,当xID2时,cIID2xID3时为cIID 3xID }}?

我认为0在此代码中始终为xID,但data I = I { iID :: Int } deriving Show data C = C { i :: I} deriving Show x = I 0 aC2 = C (I 2) aC3 = C (I 3) aC5 = C (I 5) xID = iID x cConverter aC = "Point: " ++ pID where pID :: String pID = case cIID of xID -> "X" _ -> show cIID cIID = iID . i $ aC -- xID = iID x 在案例条件下使用此内容时是否意味着其他内容?

清除样本

这是更清晰的代码,没有调试消息

Bug.hs:22:7: Warning:
    Pattern match(es) are overlapped
    In a case alternative: _ -> ...

第1点

GHCi警告我:

xID

似乎_重叠case 但为什么xID重叠了孔?

无论如何,我通过使用警卫而不是JSON.stringify来避免这个问题。 但是,我无法理解我的代码会发生什么。

1 个答案:

答案 0 :(得分:6)

case

case cIID of
        xID -> ...
        _ -> ...

引入了一个名为xID的新局部变量,该变量与全局xID无关。此外,由于它是一个变量,它可以捕获所有内容:分支_ -> ...永远不会被占用。

请改用:

case cIID of
        xID' | xID' == xID -> ...
        _ -> ...

或者更简单地说,

if cIID == xID
then ...
else ...

关于"为什么"它以这种方式工作:

考虑代码

foo :: Either Int String -> Int
foo e = case e of
   Left x  -> x
   Right y -> length y

这是一个很好的总函数:无论参数Int的值是什么,它总是会返回e

现在假设我在稍后添加代码

x :: Int
x = 42

这不应该打破foo!但是,如果x中的Left x现在被解释为42,则函数foo将会崩溃,例如Left 43

因此,模式匹配总是引入新变量,它永远不会对预先存在的变量执行相等性检查。为此,请使用像x | x == y -> ...这样的警卫。