函数式编程之-模式匹配(Pattern matching)

编者:C# 7.0也加入了模式匹配,来源于F#。


模式匹配在F#是非常普遍的,用来对某个值进行分支匹配或流程控制。


模式匹配的基本用法

模式匹配通过match...with表达式来完成,一个完整的模式表达式长下面的样子:


match [something] with
| pattern1 -> expression1
| pattern2 -> expression2
| pattern3 -> expression3

当你第一次使用模式匹配,你可以认为他就是命令式语言中的switch...case或者说是if...else if...else。只不过模式匹配的能力要比switch...case强大的多。
考虑下面的例子:


let x =
    match 1 with
    | 1 -> "a"
    | 2 -> "b" 
    | _ -> "z"

显然,x此时的值是"a",因为第一个匹配分支就匹配正确了。在这个表达式里第三个匹配分支有点特殊:


| _ -> "z"

通配符_在这里起到了default的作用,上面的所有分支如果都匹配失败,则最终会匹配的这个分支。
1.分支是有顺序的
但是这三个分支的顺序是可以随便改的,也就意味着我们可以把通配符分支放到第一个位置:


let x =
   match 1 with
   | _ -> "z"
   | 1 -> "a"
   | 2 -> "b"

在这个例子中,第一个匹配分支会胜出,同时编译器也会给出一个警告:其他的分支从来都不会被用到。
这说明在模式匹配中,分支的顺序是非常重要的,应该把更加具体的匹配分支放在前面,包含通配符的分支应该放在最后面。
2.模式匹配是一个表达式
模式匹配是一个表达式,所有的分支都应该返回同样的类型,考虑下面的例子:


let x =
    match 1 with
    | 1 -> 42
    | 2 -> true  // error wrong type
    | _ -> "hello" // error wrong type

不同的分支应该返回想通类型的值。
3.至少有一个分支能被匹配到
考虑下面的例子:


let x =
    match 42 with
    | 1 -> "a"
    | 2 -> "b"

由于两个分支都没有匹配到,编译器将会给出警告,你至少要写一个能够匹配到的分支,例如为其添加通配符分支。
你可以通过添加通配符分支让编译器不在发出警告,但是在实际实践中,你应该尽可能的添加可能存在的分支,例如你在对一个选择类型做模式匹配:


type Choices = A | B | C
let x =
    match A with
    | A -> "a"
    | B -> "b"
    | C -> "c"

如果后来某一天你在Choices类型里添加了一个新的选项D,编译器就会对之前的对Choices的模式匹配发出警告,提示你添加新的分支。试想如果你之前加了通配符,编译器就会吞掉这个警告,进而产生bug。

匹配元组(Tuple)

模式匹配几乎可以匹配F#所有的类型,例如元组:


let y =
    match (1,0) with
    | (1,x) -> printfn "x=%A" x
    | (_,x) -> printfn "other x=%A" x

显然第一个分支会被匹配到。
你可以把多个模式写在同一个分支上,当多个模式是的关系时用|隔开:


type Choices = A | B | C | D
let x =
    match A with
    | A | B | C -> "a or b or c"
    | D -> "d"

当多个模式是的关系时用&隔开:


let y =
    match (1,0) with
    | (2,x) & (_,1) -> printfn "x=%A" x


匹配list

匹配list只有三种模式:

  • [x;y;z]用来显示匹配list中的元素

  • head::tail head会匹配到第一个元素,其他的元素会匹配到tail,这个模式常用来对list做递归

  • [] 会匹配到空的list


let rec loopAndPrint aList =
    match aList with
    | [] ->
        printfn "empty"
    | x::xs ->
        printfn "element=%A," x
        loopAndPrint xs
loopAndPrint [1..5]

当[]模式被匹配到,说明list已经为空,可以作为递归的终止条件;
x::xs模式会将第一个元素匹配到x中,剩余的元素被匹配到xs,然后xs又被当做参数做下一次递归


匹配Recoard type和Descriminated Union type...


//record type
type Person = {First:string; Last:string}
let person = {First="john"; Last="doe"}
match person with
| {First="john"}  -> printfn "Matched John"
| _  -> printfn "Not John"
//union type
type IntOrBool= I of int | B of bool
let intOrBool = I 42
match intOrBool with
| I i  -> printfn "Int=%i" i
| B b  -> printfn "Bool=%b" b


其他

1.as关键字
你可以把模式用as关键字指向另一个名称:


let y =
    match (1,0) with
    | (x,y) as t ->
        printfn "x=%A and y=%A" x y
        printfn "The whole tuple is %A" t

2.匹配子类
:?用来匹配类型,例如第一个分支用来匹配int类型:


let detectType v =
    match box v with
        | :? int -> printfn "this is an int"
        | _ -> printfn "something else"

匹配类型并不是一种好的实践,正如你在OO语言里编写if type ==...一样。
when条件
有时候你需要对匹配完成的值做一些条件判断:


let elementsAreEqual aTuple =
    match aTuple with
    | (x,y) ->
        if (x=y) then printfn "both parts are the same"
        else printfn "both parts are different"

这种情况可以通过在模式中添加when条件来做到:


let elementsAreEqual aTuple =
    match aTuple with
    | (x,y) when x=y ->
        printfn "both parts are the same"
    | _ ->
        printfn "both parts are different"


Active pattern

when语句尽管可以给模式添加一些条件,但是当语句过于复杂的时候可以考虑某个分支的模式定义为一个方法:


open System.Text.RegularExpressions
// create an active pattern to match an email address
let (|EmailAddress|_|) input =
   let m = Regex.Match(input,@".+@.+")
   if (m.Success) then Some input else None 
// use the active pattern in the match 
let classifyString aString =
    match aString with
    | EmailAddress x ->
        printfn "%s is an email" x
         
    // otherwise leave alone
    | _ ->
        printfn "%s is something else" aString
//test
classifyString "alice@example.com"
classifyString "google.com"

原文地址:https://www.cnblogs.com/xiandnc/p/9388259.html

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/320614.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P4123-[CQOI2016]不同的最小割【网络流,分治】

正题 题目大意:https://www.luogu.com.cn/problem/P4123 题目大意 一张无向图,求所有点对之间有多少不同的最小割。 解题思路 考虑分治的做法,如果我们得知了(s,t)(s,t)(s,t)的最小割www,并且剩下的残量网络中连通点集SSS与sss连通&#x…

【DP】饥饿的WZK(jzoj 1998)

饥饿的WZK jzoj 1988 题目大意&#xff1a; 有很多个点&#xff0c;并且给出n个区间&#xff0c;问在选的区间不重复的前提下&#xff0c;选的区间的点数总和最大是多少 输入样例 3 1 3 7 8 3 4输出样例 5数据范围 对于100%的数据&#xff1a;1<N<2000&#xff0c…

ACM-ICPC 2018 徐州赛区网络预赛 D. EasyMath

ACM-ICPC 2018 徐州赛区网络预赛 D. EasyMath 做法&#xff1a;\[f(m,n) \sum _{i1}^{m} \mu(in) \sum_{i1}^{m}[gcd(i,n)1]\mu(i)\mu(n) \mu(n)\sum_{d|n}\mu(d)f(\frac{m}{d},d)\] 边界: n1&#xff0c;杜教筛求\(\sum_{i1}^{m}\mu(i)\)&#xff0c;m 1, 返回\(\mu(n)\)&…

51nod1601-完全图的最小生成树计数【Trie,分治】

正题 题目链接:http://www.51nod.com/Challenge/Problem.html#problemId1601 题目大意 nnn个点的完全图&#xff0c;边(i,j)(i,j)(i,j)的权值为aixoraja_i\ xor\ a_jai​ xor aj​。求最小生成树和方案数。 解题思路 对于一个高位数&#xff0c;将这一位为000和这一位为111分…

纪中C组模拟赛总结(2019.7.8)

成绩&#xff1a; 注&#xff1a; rankrankrank是有算其它dalaodalaodalao的 hkydalaohkydalaohkydalao竟不屑于交代码 rankrankranknamenamenamescorescorescoreT1T1T1T2T2T2T3T3T3T4T4T4171717wjjwjjwjj185185185100100100858585000000212121lyflyflyf170170170100100100707…

HDU5442

HDU5442 做法&#xff1a;把原串复制一份加在后边&#xff0c;中间插特殊入个特殊字符&#xff0c;再把翻转后的串加在后边&#xff0c;同样复制一份。然后做后缀数组&#xff0c;按题意处理细节即可。 #include <cstdio> #include <iostream> #include <algori…

Asp.Net Core SignalR 与微信小程序交互笔记

什么是Asp.Net Core SignalRAsp.Net Core SignalR 是微软开发的一套基于Asp.Net Core的与Web进行实时交互的类库&#xff0c;它使我们的应用能够实时的把数据推送给Web客户端。功能自动管理连接允许同时广播到所有客户端也可以广播到指定的组或者特定的客户端在Github上开源&am…

手机(jzoj 1983)

手机 jzoj 1983 题目大意&#xff1a; 在手机输入键盘上有很多键&#xff08;如下图&#xff09;&#xff0c;每一个位置按一次就是第一个字母&#xff0c;第二次就是第二个字母&#xff08;空格按0一次&#xff09;&#xff0c;现在问打出一条信息最少按几下&#xff1f; …

P2371-[国家集训队]墨墨的等式【同余最短路】

正题 题目链接:https://www.luogu.com.cn/problem/P2371 题目大意 nnn个aia_iai​&#xff0c;求有多少个b∈[l,r]b\in[l,r]b∈[l,r]满足∑i1naixib\sum_{i1}^na_ix_ib∑i1n​ai​xi​b有正整数解。 解题思路 因为有一个a1a_1a1​在&#xff0c;而且x1x_1x1​可以是任意正整数…

HDU5514 Frogs

HDU5514 Frogs 题意&#xff1a;将\([0,m)\)所有符合\(a[i]*t ~mod~ m\)的值求和 做法&#xff1a; \(a[i]*t ~mod~ m\) 会在 \(gcd(a[i],m)\) 的倍数出现&#xff0c;因此问题等价与求&#xff1a;\[ \sum_{i1}^{m-1} [ [(a[1],m)|i] or [(a[2],m)|i] or ... or [(a[n],m)|i] …

HDU5573

HDU5573 做法&#xff1a;本题的关键在于题目限制了n≤2^k&#xff0c;如果可以不选的话&#xff0c;我就会用最左边的1&#xff0c;2&#xff0c;4...凑出n&#xff0c;这里需要用减法&#xff0c;于是先把所有的数都加到答案里&#xff0c;这个值与n的插值&#xff0c;就是我…

【结论】游戏(jzoj 1984)

游戏 jzoj 1984 题目大意&#xff1a; 有很多个点&#xff0c;两个人每次可以取走2k2^k2k&#xff08;k是一个自然数&#xff0c;可以自己选&#xff09;个点&#xff0c;取走最后一个点的人胜利&#xff0c;现在你先选&#xff0c;问你是否能赢&#xff08;能赢输出MaoLaoD…

Go vs .NET Core 2.1

.NET Core 2.1 正式发布之际&#xff0c;微软团队在博客的中提到了 .NET Core 2.1 中的性能提升。这让我想起了去年 Go 语言 Iris MVC 框架作者做的 Go 与 .NET Core 2.0 之间的性能对比(具体可看https://hackernoon.com/go-vs-net-core-in-terms-of-http-performance-7535a61b…

CF786E-ALT【网络流,倍增】

正题 题目链接:https://www.luogu.com.cn/problem/CF786E 题目大意 nnn个点的一棵树&#xff0c;mmm个人每个人走一个路径。 给一些人狗或者一些边狗每个人要求要么它自己有狗要么它走的路径上都有狗。 解题思路 考虑最小割&#xff0c;其实就是要么割一个人要么割一整条路径…

HDU6038 - Function

HDU6038 - Function 做法&#xff1a; 展开后有&#xff0c;\(f(i) b_{f(a_i)} b_{b_{f(a_{a_i})}} ... b_{b_{..b_{f(i)}}}\)&#xff0c;可以发现当 \(a_i\) 所在的循环节中确定一个时&#xff0c;整个循环都确定了&#xff0c;根据这个式子还可以发现&#xff0c;对于一…

.NET Core TDD 前传: 编写易于测试的代码 -- 依赖项

第1篇: 讲述了如何创造"缝". "缝"(seam)是需要知道的概念.第2篇, 避免在构建对象时写出不易测试的代码.本文是第3篇, 讲述依赖项和迪米特法则.迪米特法则 (Law of Demeter)还是使用建造汽车的例子. 生产汽车的时候需要轮胎, 组装时需要什么型号的轮胎, 就…

【dfs】家族(jzoj 1985)

家族 jzoj 1985 解题思路&#xff1a; 在一个只含空格&#xff0c;‘*’号和小写字母的图上&#xff0c;问有多少个连在一起&#xff08;上下左右四个方向&#xff09;的小写字母块 输入样例 4 *zlw**pxh l*zlwk*hx* w*tyy**yyyzzl输出样例 3数据范围 10%的数据&#xf…

51nod1325-两棵树的问题【最大权闭合图,网络流】

正题 题目链接:http://www.51nod.com/Challenge/Problem.html#problemId1325 题目大意 两棵树。要求选出一组权值和最大的点使得这两个点集在两棵树上都是连通的。 解题思路 我们枚举一个中间点iii&#xff0c;然后从这个点开始扩展连通块。那么如果这个点作为根的话&#x…

【背包】作业(jzoj 1986)

作业 jzoj 1986 解题思路&#xff1a; ‘光光’在暑假有很多作业&#xff0c;但他不能全部做完&#xff0c;他只有一定的时间&#xff0c;某一项作业没做完&#xff08;有一点没做完也算&#xff09;&#xff0c;他就会有一个不开心值&#xff0c;现在问不开心值最小是多少 …

HDU5875 - Function

HDU5875 - Function 做法&#xff1a;st表二分的经典题。不能使用数学函数log&#xff0c;否则会tle&#xff0c;需要预处理 #include <bits/stdc.h> #define rep(i,a,b) for(int ia;i<b;i) #define per(i,a,b) for(int ia;i>b;--i) #define mem(a,b) memset(a,b,s…