【PL理论】(12) F#:模块 | 命名空间 | 异常处理 | 内置异常 |:? | 相互递归函数

news2024/11/26 12:36:26

 

  • 💭 写在前面:本章我们将介绍 F# 的模块,我们前几章讲的列表、集合和映射都是模块。然后我们将介绍 F# 中的异常,以及内置异常,最后再讲解一下相互递归函数。

目录

0x00 F# 模块(Module)

0x01 F# 异常处理(Exception)

0x02 内置异常(Built-in Exceptions)

0x03 相互递归函数

0x04 通过泰勒级数展开来逼近计算 e^x


0x00 F# 模块(Module)

用于代码组织和抽象的特性,模块 (Module) 就是相关类型、值和函数的集合。

类似于面向对象编程中的类,但没有对象的概念。

比如我们说的的列表、集合和映射都是模块。

在这个章节后,我会给出一点练习题,方便大家更好地掌握 F# 基础。

为了方便大家没有负担地有效练习,我会在框架代码中勾勒出模块,你只需要填写就行了:

namespace DataStructure

module Queue =
  type t = int list * int list
  let empty: t = ([], [])
  let enqueue (i: int) (queue: t) = ...

另外,这个 namespace 就是命名空间,类似于 C++。

0x01 F# 异常处理(Exception)

F# 中也是可以 raise 捕获异常的,raise ... 会被求值为一个异常并传播。

使用 try-with 来捕获引发的异常,异常会被视为 any type,可以是任何类型 ( `a ) 。 

exception DivByZero

let div (x: int) (y: int) : int =
  if y = 0 then raise DivByZero else x / y

let printDiv (x: int) (y: int) : unit =
  try printfn "%d" (div x y) with
  | DivByZero -> printfn "Divisor is zero" 

0x02 内置异常(Built-in Exceptions)

F# 有不少预定义的异常,要捕获这些错误,你必须使用 |:? 

这是因为 F# 与 C# (.NET) 都是一个爹有着密不可分的关系。

这里提供几种还不错的选择,让你避免记住这些复杂的异常名称:

let doFind1 (k: string) (m: Map<string,int>) : int =
  try Map.find k m with
  | :? System.Collections.Generic.KeyNotFoundException -> 0

let doFind2 (k: string) (m: Map<string,int>) : int =
  if Map.containsKey k m then Map.find k m else 0

let doFind3 (k: string) (m: Map<string,int>) : int =
  match Map.tryFind k m with
  | None -> 0 | Some i -> i

0x03 相互递归函数

相互递归函数 (Mutually Recursive Function),指的是多个函数可以相互递归调用。

简单来说就是你递归调用我,我递归调用你,用 let rec ... and 语法来定义这样的函数。

💬 举个例子:我们来定义三个相互递归的函数

let rec f x =
  x + g (x - 1)

and g y =
  if y <= 1 then 1 else y * h (y - 1)

and h z =
  if z <= 2 then 0 else f (z - 1) + f (z - 2)

这段代码定义了三个相互递归的函数 f,g,h,它们彼此之间互相调用。

形成了一个循环,每个函数的返回值都依赖于其他函数的返回值,从而实现了相互递归。

0x04 通过泰勒级数展开来逼近计算 e^x

通过泰勒级数展开来逼近计算 e^x

① 首先计算 n 的阶乘:

n!=n\times (n-1)\times(n-2)\times...\times2\times1

我们定义一个递归函数 Fac 计算一个非负整数的阶乘,当输入值 n\leq 1 时,返回1。

否则,返回 n 乘以 (n-1)  的阶乘。

在 Tylor 函数中,Fac 被用来计算泰勒级数展开的分母部分,即 n!  。

② 再通过泰勒级数展开公式 (以 e 为底的指数函数) ,我们展开前十项:

e^x=\sum_{n=0 }^{\infty }\frac{x^n}{n!}\, \, \, \Rightarrow \, \, \, e^x\approx \sum_{n=0 }^{10}\frac{x^n}{n!}

再定义一个递归函数 Taylor 计算 e^x 的泰勒级数展开,当展开的级数项数 n=0 时,返回 1.0

否则计算 x^n/n!  并加上递归调用 Taylor 函数计算更低阶的项。

在 Taylor 函数中,Fac 函数被用来计算每一项的阶乘。

💬 代码演示:通过泰勒级数展开来逼近计算 e^x

let rec Fac n =
    if n <= 1 then 1
    else n * Fac (n - 1)

let rec Taylor x n =
    if n = 0 then 1.0
    else (float x ** float n) / float (Fac n) + Taylor x (n - 1)

// 计算 e^x 的值
let calculateExponential x =
    if System.Double.IsNaN(x) || System.Double.IsInfinity(x) then
        invalidArg "x" "x must be a finite number"
    else
        Taylor x 10  // 前10项

这两个函数就相互递归了,因为 Taylor 调用了 Fac 来计算阶乘,而 Fac 也会调用 Taylor。

你可以发现,我们没有使用刚才讲的 "0x03 相互递归",let rec ... and。

因为每次计算阶乘都会重新计算泰勒级数的一部分,导致大量的重复计算:

let rec Fac n =
    if n <= 1 then 1
    else n * Taylor (n - 1) 1

and Taylor x n =
    if n = 0 then 1.0
    else (float x ** float n) / float (Fac n) + Taylor x (n - 1)

// 计算 e^x 的值
let calculateExponential x =
    if System.Double.IsNaN(x) || System.Double.IsInfinity(x) then
        invalidArg "x" "x must be a finite number"
    else
        Taylor x 10  // 前10项

// 测试计算函数
let result = calculateExponential 1.0
printfn "e^1 的值近似为: %f" result


📌 [ 笔者 ]   王亦优
📃 [ 更新 ]   2024.6.16
❌ [ 勘误 ]   /* 暂无 */
📜 [ 声明 ]   由于作者水平有限,本文有错误和不准确之处在所难免,
              本人也很想知道这些错误,恳望读者批评指正!

📜 参考资料 

Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .

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

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

相关文章

UFS协议入门-分层结构

写在前面:本文参考UFS jedec3.1,本文思维导图如下 1. 分层概述 UFS协议分为3层,从上至下分别是:应用层(UAP),传输层(UTP),互联层(UIC),具体结构如下图所示。 2.1 应用层 在应用层(UAP)中,包括:UFS指令集(UCS),设备管理器(Device Manager),任务管理器(Task Manager…

植物大战僵尸杂交版最新2.0.88手机+电脑+苹果+修改器

在这个充满奇妙的平行宇宙中&#xff0c;植物和僵尸竟然能够和谐共存&#xff01;是的&#xff0c;你没听错&#xff01;一次意外的实验&#xff0c;让这两个看似对立的生物种类发生了基因杂交&#xff0c;创造出了全新的生物种类——它们既能够进行光合作用&#xff0c;也具备…

《C++ Primer Plus》第十三章复习题和编程练习

目录 一、复习题**二、编程练习 一、复习题** 1. 派生类从基类那里继承了什么&#xff1f; 答&#xff1a;在类的继承和派生中&#xff0c;C中的派生类能够继承基类的所有数据成员和大部分成员函数。但是基类中不同访问控制权限的成员在派生中的访问权限也不相同。公有成员直…

c++|unordered系列关联式容器(unordered_set、unordered_map介绍使用+哈希结构)

目录 一、unordered_set的介绍与使用 1.1unordered_set介绍 1.2unordered_set使用 2.2.1构造 2.2.2容量 2.2.3修改 二、unordered_map的介绍与使用 2.1unordered_map介绍 2.2unordered_map使用 2.2.1构造 2.2.2容量 2.2.3修改 三、底层结构(哈希) 3.1哈希概念 3.2哈…

函数的概念及图像

注&#xff1a; 判断两函数是否相同&#xff0c;只看定义域和对应法则。 1. 函数的定义 一般的&#xff0c;在一个变化过程中有两个变量 x&#xff0c;y。如果对于x在某个变化范围内的每一个确定值&#xff0c;按照某个对应法则&#xff0c;都有唯一确定的值y和他对应。那么y就…

ChatGPT为啥不用Websocket而是EventSource?

点击下方“JavaEdge”&#xff0c;选择“设为星标” 第一时间关注技术干货&#xff01; 免责声明~ 任何文章不要过度深思&#xff01; 万事万物都经不起审视&#xff0c;因为世上没有同样的成长环境&#xff0c;也没有同样的认知水平&#xff0c;更「没有适用于所有人的解决方案…

统计信号处理基础 习题解答10-10

题目 在本题中&#xff0c;我们讨论再生PDF。回顾前面 其中分母与无关。如果选择一个&#xff0c;使得它与相乘时&#xff0c;我们得到与相同形式的PDF&#xff0c;那么后验PDF 将有和相同的形式。例10.1的高斯PDF正是这样的一种情况。现在假设在条件下的的PDF是指数形式&…

Codeforces Round 949 (Div. 2) A~D

A. Turtle and Piggy Are Playing a Game &#xff08;思维&#xff09; 题意&#xff1a; 给出一个整数 x x x &#xff0c;使得 l ≤ x ≤ r l \le x \le r l≤x≤r &#xff0c;其中 l , r l, r l,r 为给定值。同时保证 2 l ≤ r 2l \le r 2l≤r 。 执行以下操作&…

python如何输入回车

Python默认遇到回车的时候&#xff0c;输入结束。所以我们需要更改这个提示符&#xff0c;在遇到空行的时候&#xff0c;输入才结束。 raw_input就是从标注输入读取输入&#xff0c;输入的是什么就是什么。 文档解释&#xff1a; The function then reads a line from input,…

quick4 - hackmyvm

简介 靶机名称&#xff1a;quick4 难度&#xff1a;简单 靶场地址&#xff1a;https://hackmyvm.eu/machines/machine.php?vmQuick4 本地环境 虚拟机&#xff1a;vitual box 靶场IP&#xff08;quick4&#xff09;&#xff1a;192.168.56.104 跳板机IP(windows 11)&…

leetcode:不同的二叉树

class Solution { public:int numTrees(int n) {vector<int> dp(n1);dp[0] 1;dp[1] 1;for(int i 2;i < n;i){for(int j 1;j < i;j) // 当根节点为j时{dp[i] dp[j-1] * dp[i-j];}}return dp[n];} }; /* dp[i] i个不同的数组成的二叉搜索数的个数假设 i 5当根…

零基础非科班也能掌握的C语言知识19 动态内存管理

动态内存管理 1.为什么要有动态内存分配2.malloc和free2.1 malloc2.2 free 3.calloc和realloc3.1 calloc3.2realloc 4.常见的动态内存的错误4.1对NULL指针的解引用操作4.2对动态开辟空间的越界访问4.3对非动态内存开辟的空间free4.4使用free释放⼀块动态开辟内存的⼀部分4.5对同…

kNN算法-概述

所谓kNN算法就是K-nearest neigbor algorithm。这是似乎是最简单的监督机器学习算法。在训练阶段&#xff0c;kNN算法存储了标签训练样本数据。简单地说&#xff0c;就是调用训练方法时传递给它的标签训练样本会被它存储起来。 kNN算法也叫lazy learning algorithm懒惰学习算法…

分享不用会员免费听歌的软件,可听付费,支持随听随下!

今天来点特别的&#xff0c;给你们带来几款全网免费听歌的神器&#xff0c;让你们的音乐之旅不再有障碍&#xff01; 现在&#xff0c;找好听的歌越来越像寻宝一样&#xff0c;动不动就得掏腰包。不过别担心&#xff0c;阿星今天就来分享几款好用的免费听歌app&#xff0c;电脑…

Linux——PXE整体流程

1.自己安装一个CentOS 8的服务器 1&#xff09;手动安装 虚拟硬件配置&#xff1a;2核CPU&#xff0c;4G内存&#xff0c;100G硬盘 2个网卡&#xff08;一个通外网&#xff0c;一个内部使用&#xff09; 软件安装&#xff1a;Server GUI 磁盘分区&#xff1a;使用逻辑卷&#…

实践分享:如何用小程序里的小组件做应用开发?

随着移动互联网的快速发展&#xff0c;小程序等轻量级应用平台日益成为用户获取信息和服务的重要渠道。而小组件也在其中扮演了至关重要的角色&#xff0c;不仅能够提升用户的交互体验&#xff0c;还能帮助开发者高效地构建功能丰富、界面美观的小程序。 本文中&#xff0c;我们…

【Uniapp】uniapp微信小程序定义图片地址全局变量

错误写法&#xff1a; main.js Vue.prototype.$imgUrl 图片地址这么写之后 就发现压根不起作用&#xff1b;获取到的是undefined 正确写法&#xff1a; 返回函数&#xff0c;后面可以拼上OSS图片完整路径 Vue.prototype.$imgUrl (url) > {return ("https://地址…

jmeter性能优化之mysql配置

一、连接数据库和grafana 准备:连接好数据库和启动grafana并导入mysql模板 大批量注册、登录、下单等,还有过节像618,双11和数据库交互非常庞大,都会存在数据库的某一张表里面,当用户在登录或者查询某一个界面时,量少的话体现不出来,量很大的时候一定会有卡的现象, 性…

SpringBoot整合RabbitMQ实现消息延迟队列

环境依赖 SpringBoot 3.1.0 JDK 17 前期准备 安装MQ: liunxdockerrabbitmq安装延迟队列插件 实例 实现延迟队列的一种方式是在 RabbitMQ 中使用消息延迟插件&#xff0c;这个插件可以让你在消息发送时设置一个延迟时间&#xff0c;超过这个时间后消息才会被消费者接收到…

期刊影响因子、分区如何查询

查询期刊影响因子、分区等信息就不得不说到的数据库JCI(Journal Citation Indicator)。 JCR 是一个综合性、多学科的期刊分析与评价报告&#xff0c;它客观地统计Web of Science收录期刊所刊载论文的数量、论文参考文献的数量、论文的被引用次数等原始数据&#xff0c;再应用文…