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

String Haskell中case语句中的模式匹配变量,string,haskell,comparison,case-statement,String,Haskell,Comparison,Case Statement,如果我使用case语句将一个字符串文本与一个字符串文本进行比较,我会得到预期的行为:如果它们相同-它匹配,如果它们不匹配-它不匹配 但是,如果将字符串文字与作为字符串的常量进行比较,则会得到“模式匹配重叠”警告,并且带有常量的分支始终匹配 下面是一个示例会话: Prelude> let var1 = "abc" Prelude> let var2 = "def" Prelude> case var1 of { var2 -> "Fail"; _ -> "Win" }

如果我使用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"
这是怎么回事?这种行为有什么意义?

这是因为“案例”并没有按照你认为的那样进行。未将设置为“def”的“var2”与“var1”进行比较。相反,您将得到一个新范围,其中包含一个绑定到“var1”值的新“var2”

产生错误消息的原因是,就编译器而言,“var2->…”和“->…”之间没有区别。两者都匹配“var1”的所有可能值。

绑定新变量。所以当你写作时:

case x of
    y -> ...
现在,您已将一个新变量“y”绑定到“x”的值。这就是微不足道的“模式”。当涉及构造函数时,您可以更清楚地看到绑定是如何工作的:

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

case x of
    "def" -> ....

请参阅Don的答案了解原因。做你想做的事情的一个常见习惯用法是:

var1 = "abc"
var2 = "def"

foo x = case () of
    () | x == var1 -> "Fail"
       | x == var2 -> "Failzor"
       | otherwise -> "WIN"
当然,在这种情况下,我们将丢失
案例
,只需直接在函数上写入保护:

foo x | x == var1 = "Fail"
      | ...
更新

如今,扩展在做这件事时,语法噪音稍微小一些

{-# LANGUAGE MultiWayIf #-}

foo x = if | x == var1 -> "Fail"
           | x == var2 -> "Failzor"
           | otherwise -> "WIN"

我想这将有助于你解释如何用变量进行符号化,或者解释选择这种行为的理论或推理。@Evan,我认为推理是关于阿尔法转换的。也就是说,我们不希望有人决定为
x
添加顶级绑定来彻底改变模式匹配的语义。我想我以前读过这篇文章——我仍处于尝试学习Haskell的阶段——你的解构示例对我来说是“哦,这就是为什么”。这很不幸。Elixir能够处理bothI-wish文档和各种教程,其中明确指出a)case语句是具有不同语法的模式匹配,b)除了表面的相似性,Haskell的case与C的switch没有任何共同之处。他们解决不同的问题。这在(免费)书中也有很好的解释。
{-# LANGUAGE MultiWayIf #-}

foo x = if | x == var1 -> "Fail"
           | x == var2 -> "Failzor"
           | otherwise -> "WIN"