F#奇妙游(30):计算表达式与ADT

news2025/2/28 17:23:17

Computation Expression More

在这里插入图片描述

F#中自定义的 Computation Expression 一共有8个语法构造,其中match!let!的语法糖。

在前面的一个帖子里CE初探我们已经介绍了 computation expression 中的绑定和返回,语法是let!return。通过使用这两个语法,我们可以实现程序逻辑,而把程序逻辑和具体的实现分离开来。翻过去再看一遍,发现还是有点不太容易理解。于是嘛,书读百遍其义自见,我们就把这个例子再来一遍。

处理int option运算的简单例子

在对int option进行算术运算时,我们要对每个变量进行模式匹配,这样就会有很多的match语句,这样的代码看起来就不太美观。这里运用 computation expression 就可以把这些match语句隐藏起来,让代码看起来更加简洁。这样说来的目的就已经清楚了,我们需要实现一个 computation expression,这个 computation expression 能够处理int option的运算。

还是上次的例子,不再赘述。

type Maybe() =
    member this.Bind(opt, func) = opt |> Option.bind func
    member this.Return v = Some v
    
let maybe = Maybe()

let rateStudent name =
    match name with
    | "isaac" -> Some 90
    | "mike" -> Some 80
    | _ -> None

let answer =
    maybe {
        let! first = rateStudent "isaac"
        let! second = rateStudent "mike"
        let! third = rateStudent "isaac"
        let total = first + second + third
        return (float total) / 3.0
    }

我们再来看看这些神秘的小东西到底是什么呢?在CE初探中,我们通过对let的语义进行分析,确定let实际上是let pattern in expressionbody | expression,然后才能把let!MaybeBind联系起来。

其实,我们可以把let!maybe所构造的Computation Expression称为一种语法糖。那么从这个意义上来看,我们就能把上面代码中的计算表达式部分重构为脱糖的版本。

let answer =
    maybe.Bind( //let! first = ...
        rateStudent "isaac",
        (fun first -> 
            maybe.Bind( //let! second = ...
                rateStudent "mike",
                (fun second -> 
                    maybe.Bind( //let! third = ...
                        rateStudent "isaac",
                        (fun third -> 
                            let total = first + second + third
                            maybe.Return ((float total) / 3.0)
                        )
                    )
                )
            )
        )
    )

从这里可以看到,let!的展开就是let pattern = maybe.Bind(expression, func)。如果还是看不清楚,通常都是看不清楚的,我们就可以用F#中最好用的代码分析工具:ADT!

遇事不决ADT之

如何ADT呢?前面已经强调过很多遍,所有的值都是表达式,所有的表达式都是ADT。

我们从函数的定义开始看。

type Maybe() =
    member this.Bind(opt, func) = opt |> Option.bind func
    member this.Return v = Some v

这里this.Bind是什么类型呢?

如果用自己来替代F#的类型推导,过程大概就是:

  1. this.Bind是一个A * B -> C的类型;
  2. 其中B自己又是一个D -> F的类型;
  3. 根据Option.bind的默认类型,可以得到AoptionFoption
  4. 最终得到this.BindT option * (T -> T' option) -> T' option的类型。

写得好看点,就是option<T> * (T -> option<T'>) -> option<T'>类型。放到F# REPL中验证一下。

type Maybe =
  new: unit -> Maybe
  member Bind: opt: 'b option * func: ('b -> 'c option) -> 'c option
  member Return: v: 'a -> 'a option

再进一步我们知道,option<T>是一个和类型。

option<T> = 
    | None 
    | Some of T

这个类的组合数等于 1 + C T 1 + C_T 1+CT ,而func参数的组合数则是 C T ′ C T C_{T'} ^ {C_T} CTCTBind函数输入参数的组合数为 ( 1 + C T ) C T ′ C T (1+C_T) C_{T'} ^ {C_T} (1+CT)CTCT ,输出参数的组合数为 C ( T ′ ) C(T') C(T),整个函数的组合数为 C T ′ ( 1 + C T ) C T ′ C T C_{T'} ^ {(1+C_T) C_{T'} ^ {C_T}} CT(1+CT)CTCT

btw. 我也不知道我为什么计算组合数,貌似没什么用啊。但是通过计算组合数,我们对于这个函数的理解就比较深刻了。我每次有什么函数不太理解的时候,都会用这种方式来分析一下,来来回回算几遍,就感觉理解多了,我这边建议试一试。

回到调用函数的地方

这个语法糖这么一分析就非常清楚了,我们的builder类,Maybe其实就是为前面的语法糖提供了ADT的实现,这个ADT就定义了在计算表达式中各变量的类型和值。比如这里的三个变量firstsecondthird,它们的类型都是int,而不是int option。所以这里面的let total = first + second + third就是一个普通的算术运算,而不是int option的运算。

但是最为神奇的是什么呢?在任何一个let!语句中,我们都可能会得到None,这个时候,整个计算表达式就会停止,而不会继续往下执行。这个语法在哪里实现的呢?这个语法在let!expression中实现的。

member Bind: opt: 'b option * func: ('b -> 'c option) -> 'c option中,如果optNone,那么func就不会被调用,而是直接返回None

那么现在有一个问题,如果那个计算表达式写成这样,会怎么样呢?

let answer =
    maybe {
        let! first = rateStudent "isaac"
        let! second = rateStudent "mike"
        let! third = rateStudent "isaac"
        first + second + third
    }

大家可以试一试。会报错,因为什么?因为不满足maybe.Bind的ADT类型,maybe.Bind的ADT类型是option<T> * (T -> option<T'>) -> option<T'>,而这里的totalint类型,不是option<T'>类型。最后那句,不用return改成什么都报错,其实就是在计算表达式中的所有式子都脱糖后都要满足Maybe对应函数的ADT。

组合数不同的物种,没法谈恋爱!

在这里插入图片描述

结论

  1. ADT分析是吃透F#的关键,所有的值都是表达式,所有的表达式都是ADT;
  2. computation expression 是一种语法糖;
  3. 可以回到语法糖的脱糖版本,然后用ADT分析来理解这个语法糖;
  4. 希望能够通过这个例子,对 computation expression 有一个更深刻的理解。

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

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

相关文章

浅谈 Spring AOP

AOP&#xff08;Aspect Oriented Programming&#xff09;&#xff1a;⾯向切⾯编程&#xff0c;它是⼀种思想&#xff0c;它是对某⼀类事情的集中处理。⽐如⽤户登录权限的效验&#xff0c;没学 AOP 之前&#xff0c;我们所有需要判断⽤户登录的⻚⾯&#xff08;中的⽅法&…

ipad必须要配原装的笔么?电容笔性价比高的品牌

众所周知&#xff0c;由于Apple pencil的出现&#xff0c;现在网上越来越多平替触控笔的出现&#xff0c;无论是价格和功能&#xff0c;几乎都很接近。很多小伙伴不知如何下手&#xff0c;不知道如何从众多品牌中挑选出适合自己的&#xff0c;今天我为大家总结几款好用平价电容…

Baklib:2023年企业知识库的新最好选择!

传统的企业知识管理方式主要是通过文件档案、会议记录、员工手册等方式来进行知识管理。这种方式的缺点是效率低下&#xff0c;信息不够及时、准确、全面&#xff0c;而且很难达到知识共享的效果。随着信息技术的发展&#xff0c;现代化的企业知识管理方式越来越受到企业的青睐…

骨传导耳机佩戴舒适吗?盘点骨传导耳机舒适度比较好的几款耳机!

相信很多年轻人和我一样&#xff0c;佩戴耳机成了日常的习惯&#xff0c;蓝牙耳机已经融入了我们的日常生活和工作。但长期戴耳机也有很多的问题存在&#xff0c;比如长时间佩戴导致耳道疼痛、甚至头痛&#xff0c;或是耳机隔音效果太好&#xff0c;导致错过身边的重要信息&…

记录aardio和Pythonl联动,为python做界面、做单exe文件的几个知识点

关于aardio的几个目录的说明 如果要aardio创建python关联程序,强烈建议新建工程向导中选择“窗口程序”+python来生成,会自动建立好目录,十分方便。 写好的python脚本或工程,直接放到py目录中,aardio中可以直接import导入该目录中的python模块,无需带目录,类似: aar…

实战ResNet:CIFAR-10数据集分类

本节将使用ResNet实现CIFAR-10数据集的分类。 7.2.1 CIFAR-10数据集简介 CIFAR-10数据集共有60 000幅彩色图像&#xff0c;这些图像是3232像素的&#xff0c;分为10类&#xff0c;每类6 000幅图&#xff0c;如图7-9所示。这里面有50 000幅图用于训练&#xff0c;构成了5个训…

概念:推理 训练 模型

训练 训练是通过从已有的数据中学习到某种能力&#xff1b; 推理 推理是简化并使用该能力&#xff0c;使其能快速、高效地对未知的数据进行操作&#xff0c;以获得预期的结果。 模型 训练是计算密集型操作&#xff0c;模型一般都需要使用大量的数据来进行训练&#xff0c;通…

婚恋相亲交友红娘小程序源码开发搭建方法

目前婚恋市场基本处于兵家必争之地&#xff0c;从一二线城市到四五线城市单身男女多&#xff0c;传统婚恋相亲很多已经不满足现在年轻人市场&#xff0c;因此我们推出婚恋相亲交友小程序。 注意&#xff1a;小程序过审需ICP经营许可证。 程序支持多端&#xff1a;H5端、小程序…

go开发之个微机器人的二次开发

请求URL&#xff1a; http://域名/addRoomMemberFriend 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 参数&#xff1a; 参数名必选类型说明wId是String登录实例标识chatRoom…

国家网络安全周2023时间是什么时候?有什么特点?谁举办的?

国家网络安全周2023时间是什么时候&#xff1f; 2023年国家网络安全宣传周将于9月11日至17日在全国范围内统一开展。其中开幕式等重要活动将在福建省福州市举行。今年网安周期间&#xff0c;除开幕式外&#xff0c;还将举行网络安全博览会、网络安全技术高峰论坛、网络安全微视…

计算机竞赛 基于深度学习的动物识别 - 卷积神经网络 机器视觉 图像识别

文章目录 0 前言1 背景2 算法原理2.1 动物识别方法概况2.2 常用的网络模型2.2.1 B-CNN2.2.2 SSD 3 SSD动物目标检测流程4 实现效果5 部分相关代码5.1 数据预处理5.2 构建卷积神经网络5.3 tensorflow计算图可视化5.4 网络模型训练5.5 对猫狗图像进行2分类 6 最后 0 前言 &#…

SpringMVC的增删改查的案例

目录 前言&#xff1a; 1.总体思路&#xff1a; 2.前期准备 3.前台页面 前言&#xff1a; 我们今天来学习研究SpringMVC的增删改查&#xff0c;希望这篇博客能够帮助正在学习&#xff0c;工作的你们&#xff01;&#xff01;&#xff01; 1.总体思路&#xff1a; 首先我们得…

在linux上挂载windows共享目录

挂载要求 非root用户&#xff08;普通用户&#xff09;能够读写windows共享目录&#xff0c;比如查看文件、创建文件、修改文件、删除文件 # 让普通用户也可以正常读写 uidvalue and gidvalue Set the owner and group of the root of the file system (default: uidgid0, bu…

《算法竞赛·快冲300题》每日一题:“附近的牛”

《算法竞赛快冲300题》将于2024年出版&#xff0c;是《算法竞赛》的辅助练习册。 所有题目放在自建的OJ New Online Judge。 用C/C、Java、Python三种语言给出代码&#xff0c;以中低档题为主&#xff0c;适合入门、进阶。 文章目录 题目描述题解C代码Java代码Python代码 “ 附…

学习笔记——Java入门第三季

1.1 Java异常简介 异常&#xff1a;有异于常态&#xff0c;和正常情况不一样&#xff0c;有错误出现&#xff0c;阻止当前方法或作用域。 异常处理&#xff1a;将出现的异常提示给编程人员与用户&#xff0c;使原本将要中断的程序继续运行或者退出。并且能够保存数据和释放资源…

独家!网络机顶盒什么牌子好?热门网络电视机顶盒排名TOP5

电视机搭配网络机顶盒看剧是很多人的消遣方式&#xff0c;不过在挑选网络机顶盒时很多人踩过雷&#xff0c;像卡顿、死机、广告多等问题频发&#xff0c;近来很多人咨询我网络机顶盒什么牌子好&#xff0c;我以销量为基础盘点了网络电视机顶盒排名&#xff0c;哪些品牌最受欢迎…

OpenResume简历解析官方技术文档(翻译)

OpenResume简历解析官方技术文档(翻译) 本文是对OpenResume建立解析器官方技术文档《Resume Parser Playground》的翻译。 相关连接&#xff1a; OpenResume官网 OpenResume简历解析器的官方地址 OpenResume的Github 简历解析测试环境 该测试环境展示了 OpenResume 简历…

新型人工智能技术让机器人的识别能力大幅提升

原创 | 文 BFT机器人 在德克萨斯大学达拉斯分校的智能机器人和视觉实验室里&#xff0c;一个机器人在桌子上移动一包黄油玩具。通过达拉斯分校计算机科学家团队开发的新系统&#xff0c;机器人每推动一次&#xff0c;就能学会识别物体。 新系统允许机器人多次推动物体&#xf…

后端/DFT/ATPG/PCB/SignOff设计常用工具/操作/流程及一些文件类型

目录 1.PD/DFT常用工具及流程 1.1 FC和ICC2 1.2 LC (Library compiler) 1.3 PrimeTime 1.4 Redhawk与PA 1.5 Calibre和物理验证PV 1.6 芯片设计流程 2.后端、DFT、ATPG的一些常见文件 2.1 LEF和DEF 2.2 ATPG的CTL和STIL 2.3 BSDL 2.4 IPXCT 3.PCB设计的一些工作和工…

宏定义天坑记录

宏定义天坑记录 事件原委与推理过程 在编译一个使用了Protobuf的项目时出现了如下报错 [ybVM-8-7-centos boost_searcher]$ make g -o http_server http_server.cc data/raw_html.pb.cc -stdc11 -lboost_system -lboost_filesystem -lpthread -ljsoncpp -lprotobuf In file…