Haskell中case语句中的模式匹配变量

Max*_*x K 11 string comparison haskell case-statement

如果我使用case语句将字符串文字与字符串文字进行比较,我会得到预期的行为:如果它们是相同的 - 它匹配,如果它们不匹配 - 它不匹配.

但是,如果我将字符串文字与作为字符串的常量进行比较,则会得到"模式匹配重叠"警告,并且具有常量的分支始终匹配.

这是一个示例会话:

Prelude> let var1 = "abc"
Prelude> let var2 = "def"
Prelude> case var1 of { var2 -> "Fail"; _ -> "Win" }

<interactive>:1:0:
    Warning: Pattern match(es) are overlapped
             In a case alternative: _ -> ...
"Fail"
Prelude> case "abc" of { var2 -> "Fail"; _ -> "Win" }

<interactive>:1:0:
    Warning: Pattern match(es) are overlapped
             In a case alternative: _ -> ...
"Fail"
Prelude> case "abc" of { "def" -> "Fail"; _ -> "Win" }
"Win"
Run Code Online (Sandbox Code Playgroud)

同时,如果表现如预期:

> Prelude> if var1 == var2 then "Fail" else "Win" 
"Win"
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?这种行为有什么意义?

luq*_*qui 26

请看Don的答案.做你想要做的事情的一个常见习语是:

var1 = "abc"
var2 = "def"

foo x = case () of
    () | x == var1 -> "Fail"
       | x == var2 -> "Failzor"
       | otherwise -> "WIN"
Run Code Online (Sandbox Code Playgroud)

当然在这种情况下我们会丢失case并直接在函数上写下警卫:

foo x | x == var1 = "Fail"
      | ...
Run Code Online (Sandbox Code Playgroud)

UPDATE

这些天,MultiWayIf扩展实现了这一点,语法噪音略低.

{-# LANGUAGE MultiWayIf #-}

foo x = if | x == var1 -> "Fail"
           | x == var2 -> "Failzor"
           | otherwise -> "WIN"
Run Code Online (Sandbox Code Playgroud)


Don*_*art 21

Haskell中的模式匹配绑定了新变量.所以当你写:

case x of
    y -> ...
Run Code Online (Sandbox Code Playgroud)

你现在已经将一个新变量'y'绑定到'x'的值.这是微不足道的"模式".您可以更清楚地看到绑定构造函数时绑定的工作原理:

case x of 
    (a, b) -> ...
Run Code Online (Sandbox Code Playgroud)

现在a和b绑定到元组的组件.等等,用于解构和绑定其他数据类型.因此,要匹配字符串文字,您可以写:

case x of
    "def" -> ....
Run Code Online (Sandbox Code Playgroud)


Pau*_*son 8

那是因为"案例"没有按照你的想法行事.设置为"def"的"var2"未与"var1"进行比较.相反,您将获得一个新范围,其中包含一个绑定到"var1"值的新"var2".

错误消息的原因是,就编译器而言,"var2 - > ..."和"_ - > ..."之间没有区别.两者都匹配"var1"的所有可能值.

  • @Evan,我认为推理是关于Alpha转换的。也就是说,我们不希望有人决定为`x`添加顶级绑定,以大幅改变我们的模式匹配的语义。 (2认同)