编写“警卫”的首选方法是哪种?

时间:2011-12-10 23:22:14

标签: haskell

我已经创建了一个函数,我可以使用(据我所知)案例表达或守卫。

foo a b c = case a of 1 -> [...]
                      2 -> [...]
                      3 -> [...] 
                      [...]
                      otherwise -> error "..."

foo a b c | a == 1 = [...]
          | a == 2 = [...]
          | a == 3 = [...] 
          | [...]
          | otherwise = error "..."

所以,问题是:那两个(案件或警卫)中的哪一个是“更好”的编码?两者基本相同吗?

2 个答案:

答案 0 :(得分:13)

第一个被认为是更好的风格,原因有两个。

首先:很多人会说它看起来更好,因为你不必输入所有的==。当然,这是一个非常主观的原因。此外,您通常不会引入新的case语句,只是匹配函数参数列表中的参数,如下所示:

foo 1 b c = ... -- etc
...
foo _ b c = ... -- for the "otherwise" part

这使得代码更加紧凑和易读,很多人都喜欢。

其次,实际上存在语义差异。想象一下,你有这样的数据类型:

data Cake = Apple | Cheese | Cream

如果使用第一种方法,则匹配case..of表达式中的构造函数:

case a of
  Apple -> "fruit"
  _     -> "not fruit"

但是,如果你试图做某种有保障的表达,比如:

| a == Apple = "fruit"
| otherwise  = "not fruit"

...它确实无法正常工作,因为Cake类型没有Eq个实例,因此您无法使用==比较两个值。在数据定义之后引入Eq实例(在deriving (Eq)之后)并不总是需要,因此在这种情况下不必执行此操作可能很重要。

答案 1 :(得分:9)

当一个守卫可以被重写为其中一个参数的(无保护)案例陈述时,这不是必要的。即你可以把它写成:

foo 1 b c = [...]
foo 2 b c = [...]
foo 3 b c = [...]
[...]

这是写它的首选方式。当您想要的条件不能表示为模式时,您将使用警卫。当你需要匹配其中一个参数以外的东西时,你会使用case语句。