在我的代码中,值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"
?
更确切地说,当xID
为2
时,cIID
为2
,xID
为3
时为cIID
3
为xID
}}?
我认为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: _ -> ...
GHCi警告我:
xID
似乎_
重叠case
但为什么xID重叠了孔?
无论如何,我通过使用警卫而不是JSON.stringify
来避免这个问题。
但是,我无法理解我的代码会发生什么。
答案 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 -> ...
这样的警卫。