2010-08-13 38 views
11

如果我使用case语句将字符串文字与字符串常量进行比较,我会得到预期的行为:如果它们相同 - 如果它们不匹配 - 则不匹配。Haskell中的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" 

同时,如果行为与预期相同:

> Prelude> if var1 == var2 then "Fail" else "Win" 
"Win" 

这是怎么回事?这种行为如何有意义?

+0

谢谢,先生们。您解释了发生了什么以及如何将输入字符串与硬编码值匹配。 – 2010-08-14 08:05:35

+1

我希望在文档和各种教程中明确指出:a)case语句与不同语法的模式匹配; b)除表面相似之外Haskell的情况与C的开关没有任何共同之处。他们解决不同的问题。 – 2010-08-14 08:17:51

+0

这在(免费)书[Real World Haskell](http://book.realworldhaskell.org/read/defining-types-streamlining-functions.html#id587485)中也有很好的解释。 – Flow 2012-08-22 20:53:32

回答

8

这是因为“案件”没有做你认为的事。被设置为“def”的“var2”没有与“var1”进行比较。相反,您将得到一个新的作用域,其中包含一个绑定到“var1”值的新“var2”。

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

+0

我认为这会对你解释如何用变量象征性地做这件事,或者解释选择这种行为的理论或推理是有帮助的。 – 2010-08-13 17:09:02

+0

*叹* *我真的需要学习打字速度更快。 – 2010-08-13 17:09:17

+1

@Evan,我认为推理是关于alpha转换的。也就是说,我们不希望某人决定为'x'添加顶级绑定,以彻底改变模式匹配的语义。 – luqui 2010-08-13 23:29:31

18

Pattern matching in Haskell绑定新变量。所以当你写:

case x of 
    y -> ... 

你现在已经绑定了一个新的变量'y'值'x'。这是微不足道的“模式”。您可以更清楚地看到当涉及构造函数时绑定的工作方式:

case x of 
    (a, b) -> ... 

现在a和b绑定到元组的元素。等解构和绑定其他数据类型。 因此,匹配一个字符串字面量,你可以这样写:

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

我想我之前读过这篇文章 - 我仍然处于我想要学习Haskell的阶段 - 你解构的例子是“哦,这就是为什么”对我来说。 – 2010-08-13 17:42:33

21

见唐的回答为什么。做你正在尝试做一个常见的成语是:

var1 = "abc" 
var2 = "def" 

foo x = case() of 
    () | x == var1 -> "Fail" 
     | x == var2 -> "Failzor" 
     | otherwise -> "WIN" 

当然,在这种情况下,我们就失去了case而直接写警卫功能:

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

UPDATE

这些日子MultiWayIf扩展做到这一点,语法噪音略低。

{-# LANGUAGE MultiWayIf #-} 

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