模式匹配
不要混淆正则表达式
在编程时,匹配具有特定形式的表达式(如序列或树结构)通常很有用,而不是费力地用条件解析它们。模式匹配的目的是匹配表情与模式而且绑定成功匹配的变量。例如,如果我们有一个列表处理函数,而不是显式地测试是否存在头部和尾部,然后显式地访问头部和尾部,我们可以简单地询问输入列表是否具有具有头部和尾部的列表模式,如果是,立即使用绑定值进行计算。模式匹配还没有被广泛采用,但在OCaml、Haskell、f#和Mathematica等现代函数式语言中特别有用。
原始的模式
最简单的模式可能只是匹配一个特定的常数,或者将任意表达式绑定到变量。
下面是fibonacci函数的递归haskell构造:
1 2 3撒小谎0=0撒小谎1=1撒小谎n=撒小谎(n-1)+撒小谎(n-2)
请注意在haskell中,
=
代表定义,而不是赋值。
通配符
通配符匹配任何表达式。它的优点是不绑定任何表达式。
在haskell中,通配符写为_
这个函数在2处取值为1在其他地方取值为0
1 2fancyF2=1fancyF_=0
这里要学习的另一个教训是,haskell matches尝试从顶部一个接一个地匹配模式。所以,当
fancyF 2
它不会匹配通配符。
使用构造函数
构造函数是子从更简单的数据结构创建数据结构。构造函数的例子包括:
.
列表
每一张表都写在表格里[a1, a2, a3…]一个)
只是语法糖吗a1, a2, a3::: []
在哪里[]
是空列表。
下面是我如何获取列表中以0开头的所有元素,除了最后两个元素。
1 2 3 4 5列表=[[0,0,1]、[1,2,3.]、[0,1,2,3.]、[1,2,3.,4,5]]y=[xs|0:xs<-列表]——y绑定到[[0,1],[1,2,3]]
这种类型的模式匹配真正酷的用途是创建递归函数定义。
看看如何地图定义:
1 2地图_[]=[]地图f(x:xs)=fx:地图fxs
基本思想是将函数应用于第一个元素,并将其附加到列表其余部分的映射上。当然,你必须知道空链表的映射就是空链表,不管函数是什么。
元组
在元组内部的模式匹配肯定会起作用。
下面的函数计算平面上两点之间的距离。
1距离(x1,日元)(x2,y2)=√6((x1-x2)^2+(日元-y2)^2)
其他数据类型
Haskell支持代数数据类型。由于它们是通过函子构造的,模式匹配将以类似的方式工作。
这是一个简单的日期数据类型。
1 2 3数据日期=日期IntIntInt——年、月、日showDate::日期->字符串showDate(日期y米d)=显示y++“-”++显示米++“-”++显示d
注意如下操作符++
不能工作。它们不是函子。它们连接列表,而不是构造列表。
警卫
属性的值必须为true的布尔表达式分支去工作。
它们可以被认为是switch/case结构的替代方案。
守卫的概念也可以看作是分段函数。
1 2 3 4撒小谎n|n= =0=0|n= =1=1|否则=撒小谎(n-1)+撒小谎(n-2)
否则
被定义为真吗
为模式
as模式允许您将一个名称绑定到整个模式,即使您想拆分它。语法是形式的var@pattern
在哪里var
整个模式绑定到的变量。
这是地图的变体。
考虑下面的代码:
1 2 3contrivedMap::([一个]->一个->b)->[一个]->[b]contrivedMapf[]=[]contrivedMapf(x:xs)=f(x:xs)x:contrivedMapfxs
这个可以写成
1 2 3contrivedMap::([一个]->一个->b)->[一个]->[b]contrivedMapf[]=[]contrivedMapf列表@(x:xs)=f列表x:contrivedMapfxs
使用模式。