首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >模式匹配和卫士有什么不同?

模式匹配和卫士有什么不同?
EN

Stack Overflow用户
提问于 2010-11-12 00:33:35
回答 3查看 12.9K关注 0票数 64

我对Haskell和函数式编程都是非常陌生的。我的问题很简单。模式匹配和卫士有什么不同?

使用模式匹配的函数

check :: [a] -> String
check [] = "Empty"
check (x:xs) = "Contains Elements"

使用guards函数

check_ :: [a] -> String
check_ lst
    | length lst < 1 = "Empty"
    | otherwise = "Contains elements"

在我看来,模式匹配和Guard在本质上是一样的。两者都计算一个条件,如果为true,将执行与其挂钩的表达式。我的理解是正确的吗?

在本例中,我可以使用模式匹配或保护来得到相同的结果。但有些东西告诉我,我在这里错过了一些重要的东西。我们总是可以用一个替换另一个吗?

谁能举个例子,模式匹配比守卫更受欢迎,反之亦然?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-11-12 00:44:22

实际上,它们从根本上是完全不同的!至少在Haskell,至少是这样。

Guard既简单又灵活:它们本质上只是一种特殊的语法,可以转换为一系列if/then表达式。您可以在if中放入任意的布尔表达式,但它们不会执行您无法使用正则guards执行的任何操作。

模式匹配可以做几件额外的事情:它们是解构数据的唯一方法,并且它们在其作用域绑定标识符。在同样的意义上,case等同于if表达式,模式匹配等同于guards表达式。声明(在顶层或类似于let表达式的形式)也是模式匹配的一种形式,“普通”定义与简单的模式(单个标识符)相匹配。

模式匹配也往往是Haskell中实际发生事情的主要方式--尝试解构模式中的数据是强制执行计算的少数事情之一。

顺便说一句,您实际上可以在顶级声明中进行模式匹配:

square = (^2)

(one:four:nine:_) = map square [1..]

这有时对一组相关的定义很有用。

GHC还结合了provides the ViewPatterns extension和GHC;您可以在绑定上下文中使用任意函数,然后对结果进行模式匹配。当然,这仍然只是常规内容的语法糖。

至于在哪里使用的日常问题,这里有一些粗略的指南:

对于任何可以直接匹配到一两个构造函数深度的东西,

  • 绝对会使用模式匹配,在这种情况下,您并不真正关心复合数据作为一个整体,而是关心大部分结构。@语法允许你将整个结构绑定到一个变量上,同时也可以对其进行模式匹配,但是在一个模式中做太多这样的事情可能会让quickly.
  • Definitely变得丑陋和不可读,当你需要基于一些与模式不整齐对应的属性进行选择时,比如比较两个Int值,看看哪一个更大。
  • 如果你只需要来自大型结构内部的一些数据,特别是如果你还需要将结构作为一个整体使用,防护和访问器函数通常比一些充满@_.
  • If的可怕模式更具可读性您需要对由不同模式表示的值执行相同的操作,但是使用方便的谓词对它们进行分类,使用带有防护的单个通用模式通常更具可读性。请注意,如果一组保护不是详尽的,则所有未通过所有保护的所有保护都将下降到下一个模式(如果有的话)。因此,您可以将常规模式与一些过滤器相结合,以捕获异常情况,然后对其他所有内容进行模式匹配,以获得您关心的细节about.
  • Definitely不要对可以通过模式进行简单检查的事情使用保护。检查空列表就是一个经典的例子,使用模式匹配就可以了。
  • 一般来说,当你有疑问的时候,只要坚持默认的模式匹配就行了,这样通常会更好。如果一个模式开始变得非常丑陋或令人费解,那么停下来考虑一下你还能怎么写它。除了使用防护之外,其他选项还包括提取子表达式作为单独的函数,或者将case表达式放在函数体中,以便将一些模式匹配的内容下推到函数上,并放在主定义之外。
票数 64
EN

Stack Overflow用户

发布于 2010-11-12 00:43:18

在我看来,模式匹配和Guard在本质上是一样的。两者都计算一个条件,如果为true,将执行与其挂钩的表达式。我的理解是正确的吗?

不完全是。首先,模式匹配不能评估任意条件。它只能检查某个值是否是使用给定的构造函数创建的。

第二,模式匹配可以绑定变量。因此,虽然模式[]可能等同于保护null lst (不使用长度,因为这不是等同的-稍后将详细介绍),但模式x:xs肯定不等同于保护not (null lst),因为该模式绑定了变量xxs,而保护不绑定这些变量。

关于使用length的注意事项:使用length检查列表是否为空是非常糟糕的做法,因为要计算需要遍历整个列表的长度,这将花费O(n)时间,而仅检查列表是否为空则需要使用null或模式匹配的O(1)时间。此外,使用``length‘只是普通的,在无限列表上不起作用。

票数 10
EN

Stack Overflow用户

发布于 2010-11-12 00:44:28

除了其他好的答案之外,我将尝试具体地介绍卫士:卫士只是语法上的糖。如果你仔细想想,你的程序中通常会有以下结构:

f y = ...
f x =
  if p(x) then A else B

也就是说,如果模式匹配,则紧跟其后的是if-then-else判别。守卫将这种辨别直接放入模式匹配中:

f y = ...
f x | p(x) = A
    | otherwise = B

(在标准库中,otherwise被定义为True )。它比if-then-else链更方便,有时它还使代码变得更简单,因此比if-then-else结构更容易编写。

换句话说,它是在另一个结构之上的糖,在许多情况下大大简化了你的代码。你会发现它消除了很多if-then-else链,使你的代码更具可读性。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4156727

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档