Var*_*jan 61 syntax haskell guard
我对Haskell和一般的函数式编程都很陌生.我的问题非常基本.Pattern Matching和Guards有什么区别?
使用模式匹配的功能
check :: [a] -> String
check [] = "Empty"
check (x:xs) = "Contains Elements"
Run Code Online (Sandbox Code Playgroud)
使用警卫的功能
check_ :: [a] -> String
check_ lst
| length lst < 1 = "Empty"
| otherwise = "Contains elements"
Run Code Online (Sandbox Code Playgroud)
对我来说,模式匹配和防护看起来基本相同.两者都评估条件,如果为true则将执行挂钩的表达式.我的理解是正确的吗?
在这个例子中,我可以使用模式匹配或防护来获得相同的结果.但是有些东西告诉我,我错过了一些重要的事情.我们可以一直替换另一个吗?
有人可以提供一些例子,其中模式匹配比警卫更受欢迎,反之亦然吗?
C. *_*ann 60
实际上,它们基本上是完全不同的!至少在Haskell,无论如何.
警卫既简单又灵活:它们本质上只是特殊的语法,可转换为一系列if/then表达式.你可以在守卫中放置任意布尔表达式,但是他们不会做任何你不能做常规的事情if.
模式匹配还有几个额外的东西:它们是解构数据的唯一方法,它们在其范围内绑定标识符.在保护等同于if表达式的同一意义上,模式匹配等同于case表达式.声明(在顶层,或类似let表达式)也是模式匹配的一种形式,"普通"定义与普通模式匹配,即单个标识符.
模式匹配也往往是Haskell中实际发生的主要方式 - 尝试以模式解构数据是迫使评估的少数因素之一.
顺便说一句,您实际上可以在顶级声明中进行模式匹配:
square = (^2)
(one:four:nine:_) = map square [1..]
Run Code Online (Sandbox Code Playgroud)
这偶尔对一组相关定义有用.
GHC还提供了ViewPatterns扩展,它结合了两者; 您可以在绑定上下文中使用任意函数,然后在结果上进行模式匹配.当然,这仍然只是通常的东西的语法糖.
至于在哪里使用的日常问题,这里有一些粗略的指南:
绝对使用模式匹配可以直接匹配一个或两个构造函数的任何东西,在那里你并不真正关心整个复合数据,但是要关心大部分结构.该@语法可以让你的整体结构绑定到一个变量,同时图案也匹配,但这样做在一个模式太多,可以得到丑陋,无法读取快.
当您需要根据某些与图案不完整对应的属性进行选择时,绝对使用防护,例如比较两个Int值以查看哪个更大.
如果你只需要来自大型结构内部的几个数据,特别是如果你还需要整个结构使用,那么守卫和访问器函数通常比一些充满@和的怪异模式更具可读性_.
如果您需要对由不同模式表示的值执行相同的操作,但使用方便的谓词对它们进行分类,则使用具有保护的单个通用模式通常更具可读性.请注意,如果一组防护措施不是详尽无遗的,那么所有防护措施失败的东西都将下拉到下一个模式(如果有的话).因此,您可以将常规模式与某些过滤器结合使用以捕获异常情况,然后对其他所有内容进行模式匹配以获取您关注的详细信息.
绝对不要使用警卫来处理可以用模式轻易检查的东西.检查空列表是典型示例,使用模式匹配.
一般来说,如果有疑问,默认情况下坚持使用模式匹配,通常会更好.如果一个模式开始变得非常丑陋或令人费解,那么请停下来考虑如何编写它.除了使用警卫之外,其他选项包括将子表达式提取为单独的函数或将case表达式放在函数体内,以便将一些模式匹配向下推到它们之外并从主要定义中推出.
sep*_*p2k 10
对我来说,模式匹配和防护看起来基本相同.两者都评估条件,如果为true则将执行挂钩的表达式.我的理解是正确的吗?
不完全的.第一种模式匹配不能评估任意条件.它只能检查是否使用给定的构造函数创建了一个值.
第二种模式匹配可以绑定变量.因此,尽管该模式[]可能是等同于保护null lst(不使用长度,因为那会不等于-后来更多),该模式x:xs肯定是不等同于后卫not (null lst)因为该模式结合的变量x和xs,其中保护不不.
关于使用的注意事项length:length用于检查列表是否为空是非常糟糕的做法,因为,要计算它需要经过整个列表的长度,这将花费O(n)时间,而只是检查列表是否为空需要O(1)时间null或模式匹配.进一步使用`length'只是普通无法在无限列表上工作.
首先,您可以将布尔表达式放在一个保护中.
例如:
与列表推导一样,布尔表达式可以在模式保护中自由混合.例如:
Run Code Online (Sandbox Code Playgroud)f x | [y] <- x , y > 3 , Just z <- h y = ...
Learn You a Haskell有一个很好的引用:
模式是确保值符合某种形式并解构它的一种方式,而防护是一种测试某个值(或其中几个)的属性是真还是假的方法.这听起来很像if语句,而且非常相似.事情是,当你有几个条件时,守卫会更具可读性,并且他们可以很好地使用模式.
除了其他好的答案之外,我将尝试具体说明警卫:警卫只是语法糖.如果你考虑一下,你的程序通常会有以下结构:
f y = ...
f x =
if p(x) then A else B
Run Code Online (Sandbox Code Playgroud)
也就是说,如果模式匹配,则紧跟在if-then-else之后.一名警卫直接将这种歧视折叠成模式匹配:
f y = ...
f x | p(x) = A
| otherwise = B
Run Code Online (Sandbox Code Playgroud)
(otherwise定义True在标准库中).它比if-then-else链更方便,有时它也使代码变得更简单,因此它比if-then-else结构更容易编写.
换句话说,它是在另一种结构之上的糖,在很多情况下大大简化了代码.你会发现它消除了很多if-then-else链并使你的代码更具可读性.
| 归档时间: |
|
| 查看次数: |
11132 次 |
| 最近记录: |