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

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

目录

[0x00 F# 模块(Module)](# 模块(Module))

[0x01 F# 异常处理(Exception)](# 异常处理(Exception))

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

[0x03 相互递归函数](#0x03 相互递归函数)

[0x04 通过泰勒级数展开来逼近计算 e^x](#0x04 通过泰勒级数展开来逼近计算 e^x)


0x00 F# 模块(Module)

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

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

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

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

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

cpp 复制代码
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 ) 。

cpp 复制代码
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) 都是一个爹有着密不可分的关系。

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

cpp 复制代码
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 语法来定义这样的函数。

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

cpp 复制代码
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)

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

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

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

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

① 首先计算 的阶乘:

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

否则,返回 乘以 的阶乘。

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

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

再定义一个递归函数 Taylor 计算 的泰勒级数展开,当展开的级数项数 时,返回

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

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

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

cpp 复制代码
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。

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

cpp 复制代码
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

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

|----------------------------------------------------------------------------|
| 📜 参考资料 Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. . |

相关推荐
Robot2513 小时前
「华为」人形机器人赛道投资首秀!
大数据·人工智能·科技·microsoft·华为·机器人
IT专业服务商9 小时前
联想 SR550 服务器,配置 RAID 5教程!
运维·服务器·windows·microsoft·硬件架构
海尔辛9 小时前
学习黑客5 分钟小白弄懂Windows Desktop GUI
windows·学习
星空寻流年9 小时前
CSS3(BFC)
前端·microsoft·css3
gushansanren9 小时前
基于WSL用MSVC编译ffmpeg7.1
windows·ffmpeg
伐尘10 小时前
【Qt】编译 Qt 5.15.x For Windows 基础教程 Visual Studio 2019 MSVC142 x64
windows·qt·visual studio
专注代码七年10 小时前
在Windows 境下,将Redis和Nginx注册为服务。
windows·redis·nginx
simple_whu16 小时前
开启WSL的镜像网络模式
windows·wsl
modest —YBW20 小时前
Ollama+OpenWebUI+docker完整版部署,附带软件下载链接,配置+中文汉化+docker源,适合内网部署,可以局域网使用
人工智能·windows·docker·语言模型·llama
code在飞20 小时前
windows 部署 Kafka3.x KRaft 模式 不依赖 ZooKeeper
windows·分布式·zookeeper·kafka