F#奇妙游(20):主动模式
F#中主动模式的三种形式
F#中有一种特殊的模式匹配,叫做主动模式(Active Pattern)。主动模式可以让我们自定义模式匹配的方式,这样可以让我们的代码更加简洁,更加清晰。主动模式有三种形式,分别是:
- 单选项主动模式
- 多选项主动模式
- 部分应用的主动模式
这三个方式的语法如下:
let (|ActivePattern|) [parameters] valueToMatch = if condition then Some ()else Nonelet (|ActivePattern1|ActivePattern2|...|) [parameters] valueToMatch =match valueToMatch with| .. -> ActivePattern1| .. -> ActivePattern2| .. -> ...let (|ActivePattern|_|) [parameters] valueToMatch = if v = p1 then Some (p2, ..., pn)else None
从最后一个开始说起
模式匹配的本质
从语义上来看,模式匹配实现的是两个部分的功能:匹配检查,值绑定。匹配检查就是检查值是否符合模式,值绑定就是把值绑定到模式中的变量上。模式匹配的本质就是这两个功能的组合。
例子一
先看下面的例子:
open Systemlet (|Int|_|) str =match Int32.TryParse(str:string) with| (true, i) -> Some i| _ -> Nonelet (|Float|_|) str =match Double.TryParse(str:string) with| (true, i) -> Some i| _ -> Nonelet (|Bool|_|) str =match Boolean.TryParse(str:string) with| (true, i) -> Some i| _ -> Nonelet testParse str =match str with| Int i -> printfn $"Int: %d{i}"| Float f -> printfn $"Float: %f{f}"| Bool b -> printfn $"Bool: %b{b}"| _ -> printfn $"Not a number/bool %A{str}"testParse "123"
testParse "123.45"
testParse "true"
testParse "abc"
这个例子的功能非常简单,就是识别一个字符串的内容,这里实现了三个模式,整数、浮点数和布尔值。然后我们可以用这三个模式来匹配字符串,如果匹配成功,就打印出来。匹配不成功,则打印对应的消息。
从这个例子,我们可以窥见主动模式的内涵,以第一个模式为例。这个定义非常类似于定义了一个函数,函数名称是(|Int|_|)
,函数的标识可以通过在fsi中输入这个这个名称来查看,val ( |Int|_| ) : str:string -> int option
。是一个输入变量为字符串,输出变量为int option
类型。
我们可以直接在fsi中调用这个函数,(|Int|_|) "123"
,返回值为Some 123
;当字符串不是整数时,返回值为None
。
那么把这个函数作为一个模式来匹配时,匹配成功就是返回Some 123
,匹配不成功就是返回None
。模式匹配的第二功能是绑定,那么这里的绑定就是把123
绑定到i
上,这样就可以在模式匹配的后面使用i
了。
这里很好的揭示了部分匹配的语法和语义。上面的例子也很好的展示了部分匹配的用法。如果配合正则表达式功能,还可以实现更有意思的功能。
例子二
open System.Text.RegularExpressionslet (|FirstMatch|_|) pattern str =let matches = Regex.Matches(str, pattern)if matches.Count > 0 then Some matches.[0] else Nonelet getPhoneNumber str =match str with| FirstMatch "1[0-9]{10}" phone -> printfn $"Phone: %A{phone.Value}"| FirstMatch "[0-9]{6,8}" phone -> printfn $"Short phone: %A{phone.Value}"| _ -> printfn $"Not a phone number %A{str}"getPhoneNumber "13981156789"
getPhoneNumber "12345678"
这个例子里面,FirstMatch
模式匹配的第一个参数是正则表达式,第二个参数是要匹配的字符串。如果匹配成功,就返绑定第一个匹配字符串,否则返回None
。
利用这个主动模式,就能实现对1打头11为手机号码和6-8位电话号码的识别。这里同样是实现了匹配和绑定两个语义。绑定的对象同样是Option对象的Value。唯一不同的是,这个模式还需要一个输入参数,也就是正则表达式。
通过这两个例子,我们可以看到部分匹配的语法和语义。比较清晰,对于实际的应用也非常有用。
单选项主动模式和多选项主动模式
对于单选项主动模式和多选项主动模式,与部分匹配的主动模式不同之处在于没有那个|_|
缺省匹配的项。
看这部分的文档时,我的第一感觉是,这两个模式没有太大作用。毕竟,匹配在F#的模式匹配中已经有非常方便的功能。为什么还需要通过主动模式来实现呢?
毕竟,这两个主动模式的绑定部分的功能,并没有太大的优势。我们先来看官方文档中提供的例子。
单选项主动模式
这个模式的例子是提取System.Drawing.Color
的RGB值。
open System.Drawing
let (|RGB|) (c:Color) =(c.R, c.G, c.B)let printRGB c =match c with| RGB (r,g,b) -> printfn $"RGB: %d{r}, %d{g}, %d{b}"
可以看到这个例子中,匹配的成分很少,更多的是提取和绑定。通过主动模式,通过参数计算得到一个元组,然后在match中绑定到三个名称上。
这里的计算和返回值,可以任意的复杂,因为与前面的部分匹配一样,(|RGB|)
同样是一个函数,这个函数的输入和输出,可以是任意类型,这个函数的计算过程也可以是任意复杂的。
最终应用match的时候,也能够得到非常清晰的语法和语义特征。并且,在这个例子中,IDE和编译器都能够提供非常好的支持。
结论,单选项主动模式的主要作用是提取被匹配对象的信息,构成新的对象,然后在match中进行绑定。这在语义上非常有一致性,匹配对象的部分信息,然后绑定到名称上。
多选项主动模式
与单选项主动模式相反,多选项主动模式更注重的是匹配,而非提取(绑定)。
let (|Even|Odd|) i =if i % 2 = 0 then Even else Oddlet printEvenOrOdd i =match i with| Even -> printfn $"Even: %d{i}"| Odd -> printfn $"Odd: %d{i}"
这里match调用的对象i,在不同的分支中直接引用,而没有进行值的转换和绑定。这里的主动模式,主要是为了匹配,而不是为了绑定。
多选项主动模式类似于enum,只是这个enum的值是在运行时计算的。这个计算过程可以是任意复杂的,只要最终返回的是一个enum值就可以了。
总结
主动模式是F#中非常有意思的一个特性。它的语法和语义都非常清晰,而且非常有用。在实际的应用中,可以大大的提高代码的可读性和可维护性。
相关文章:
F#奇妙游(20):主动模式
F#中主动模式的三种形式 F#中有一种特殊的模式匹配,叫做主动模式(Active Pattern)。主动模式可以让我们自定义模式匹配的方式,这样可以让我们的代码更加简洁,更加清晰。主动模式有三种形式,分别是…...

OLED透明屏与传统显示屏的区别:探索未来视觉体验的新里程碑
OLED透明屏作为一种新兴的显示技术,与传统显示屏相比,具有许多独特的特点和优势。 那么,在这篇文章中,尼伽便通过比较OLED透明屏和传统显示屏的区别,包括透明性、对比度、色彩表现力、节能环保等方面,为读…...

打开软件提示mfc100u.dll缺失是什么意思?要怎么处理?
当你打开某个软件或者运行游戏,系统提示mfc100u.dll丢失,此时这个软件或者游戏根本无法运行。其实,mfc100u.dll是动态库文件,它是VS2010编译的软件所产生的,如果电脑运行程序时提示缺少mfc100u.dll文件,程序…...
Python 基础 -- Tutorial(二)
5、数据结构 本章更详细地描述了一些你已经学过的东西,并添加了一些新的东西。 5.1. 更多关于Lists 列表(list)数据类型有更多的方法。下面是列表对象的所有方法: list.append(x) 在列表末尾添加一项。相当于a[len(a):] [x]。 list.extend(iterable) 通过添加可…...
11 迭代器|生成器|协程
文章目录 迭代器可迭代对象可迭代对象的本质iter()函数与 next()函数迭代器 Iterator样例 for...in...循环的本质使用的场景--斐波那契数列list和tuple也可以接收可迭代对象 生成器简介创建生成器方法一方法二总结 使用 send 唤醒 协程协程和线程差异简单实现协程greenletgeven…...

“第三方支付”详解!
第三方支付是什么?第三方支付的解释 中央银行官方解释:是与产品所在国和主要外资银行签订合同、具有一定实力和信誉保障的第三方独立机构提供的交易支持平台。在通过第三方支付平台进行的交易中,买方购买货物后,买方使用第三方平台…...
Rust之泛型、trait与生命周期
泛型是具体类型或其他属性的抽象替代。在编写代码时,可以直接描述泛型的行为,或者它与其他泛型产生的联系,而无须知晓它在编译和运行代码时采用的具体类型。 1、泛型数据类型: 们可以在声明函数签名或结构体等元素时使用泛型&am…...

GPU Microarch 学习笔记 [1]
WARP GPU的线程从thread grid 到thread block,一个thread block在CUDA Core上执行时,会分成warp执行,warp的颗粒度是32个线程。比如一个thread block可能有1024个线程,分成32个warp执行。 上图的CTA(cooperative thre…...

Transformer(一)简述(注意力机制,NLP,CV通用模型)
目录 1.Encoder 1.1简单理解Attention 1.2.什么是self-attention 1.3.怎么计算self-attention 1.4.multi-headed(q,k,v不区分大小写) 1.5.位置信息表达 2.Decoder(待补充) 3.BERT 参考文献 1.Encode…...

回归预测 | MATLAB实现BiLSTM双向长短期记忆神经网络多输入多输出预测
回归预测 | MATLAB实现BiLSTM双向长短期记忆神经网络多输入多输出预测 目录 回归预测 | MATLAB实现BiLSTM双向长短期记忆神经网络多输入多输出预测预测效果基本介绍程序设计往期精彩参考资料 预测效果 基本介绍 MATLAB实现BiLSTM双向长短期记忆神经网络多输入多输出预测&#x…...

使用Dockker创建vwas容器时报错的解决方法
执行命令 docker run -it -d -p 13443:3443 --cap-add LINUX_IMMUTABLE secfa/docker-awvs没有详细看报错之前找了各种各样的解决办法,都无法解决。因此以后在看报错提示的时候耐心一点看关键词Error 后来才发现启动vwas时docker报了这个错: OSError: …...

【数据结构OJ题】链表分割
原题链接:https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70?tpId8&&tqId11004&rp2&ru/activity/oj&qru/ta/cracking-the-coding-interview/question-ranking 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2…...
无感知发布
什么是无感知发布 "无感知发布"是指在软件系统或应用程序进行更新或升级时,尽可能地避免对用户或系统的正常运行产生影响或中断。这种发布方式通常采用一系列技术和策略,以确保新版本的软件可以平滑地替代旧版本,而不会造成用户的…...

C++ 虚继承
C棱形继承 在 C 中,在使用 多继承 时,如果发生了如果类 A 派生出类 B 和类 C,类 D 继承自类 B 和类 C,这时候就发生了菱形继承。 如果发生了菱形继承,这个时候类 A 中的 成员变量 和 成员函数 继承到类 D 中变成了两…...
git commit用法
git commit 是 Git 版本控制系统中的一个命令,用于将更改提交到本地存储库。以下是 git commit 的一些常见用法和选项: 基本用法: git commit -m "提交信息"使用 -m 选项可以直接在命令行中添加提交信息。 提交所有更改: git commit -a -m &q…...

【LeetCode】543.二叉树的直径
题目 给你一棵二叉树的根节点,返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。 两节点之间路径的 长度 由它们之间边数表示。 示例 1: 输入:root [1,2,3,4,5]…...
TypeScript教程(五)条件语句,循环,函数
一、条件语句 条件语句基于不同的条件来执行不同的动作 1.if语句:只有当指定条件为true时,使用该语句来执行代码 2.if...else语句:当条件为true时执行代码,当条件为else时执行其他代码 3.if...else if...else语句:…...

vue使用jsplumb 流程图
安装jsPlumb库:在Vue项目中使用npm或yarn安装jsPlumb库。 npm install jsplumb 创建一个Vue组件:创建一个Vue组件来容纳jsPlumb的功能和呈现。 <template><div style"margin: 20px"><div style"margin: 20px">&l…...
【BASH】回顾与知识点梳理(二十八)
【BASH】回顾与知识点梳理 二十八 二十八. 例行性工作排程(crontab)28.1 什么是例行性工作排程Linux 工作排程的种类: at, cronCentOS Linux 系统上常见的例行性工作 28.2 仅执行一次的工作排程atd 的启动at 的运作方式实际运作单一工作排程at 工作的管理batch&…...

LangChain源码逐行解密之系统(二)
LangChain源码逐行解密之系统 20.2 serapi.py源码逐行剖析 我们可以看一下Google查询的例子,在LangChain中有多种实现的方式。 如图20-5所示,在utilities的serpapi.py代码文件中实现了SerpAPIWrapper。 图20- 5 utilities的serpapi.py的SerpAPIWrapper 在langchain目录的se…...

YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】,分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...