【PL理论深化】(8) Ocaml 语言:元组和列表 | 访问元组中的元素 | 列表中的 head 和 tail | 基本列表操作符

  • 💬 写在前面:本章我们将探讨 OCaml  中的元组(tuple)和列表(list),它们是函数式编程语言中最常用的数据结构。
  • 目录

    0x00 元组(Tuple)

    0x01 访问元组中的元素

    0x02 列表(list)

    0x03 列表的 head 和 tail

    0x04 基本列表操作符


0x00 元组(Tuple)

元组 (tuple) 是值的 有序集合 (in-order set) ,例如:

元组 (1, "one") 包含了一个整数和一个字符串,其类型可以表示为 int * string

元组 (2, "two", true) 包含了一个整数, 一个字符串和一个布尔值,其类型为 int * string * bool

# let x = (1, "one");;
val x : int * string = (1, "one")
# let y = (2, "two", true);;
val y : int * string * bool = (2, "two", true)

0x01 访问元组中的元素

要访问元组的每个元素,可以使用模式匹配。

例如,可以定义如下函数 fstsnd,用于获取由两个元素组成的元组的第一个和第二个元素。

# let fst p = match p with (x,_) -> x;;
val fst : ’a * ’b -> ’a = <fun>
# let snd p = match p with (_,x) -> x;;
val snd : ’a * ’b -> ’b = <fun>

或者可以直接在函数的参数中使用元组模式,如下所示:

# let fst (x,_) = x;;
val fst : ’a * ’b -> ’a = <fun>
# let snd (_,x) = x;;
val snd : ’a * ’b -> ’b = <fun>

类型 'a * 'b -> 'a 表示函数 fst 接受一个由任意类型 {}'a 和 {}'b 组成的元组作为输入,

并返回类型为 {}'a 的值。通过函数的类型,我们可以推断出函数的大致作用。

不仅在函数参数中,还可以在 let 表达式中使用元组模式。例如,看下面的代码:

# let p = (1, true);;
val p : int * bool = (1, true)
# let (x,y) = p;;
val x : int = 1
val y : bool = true

p 代表元组 (1, true),并将其分解为 x 和 y

0x02 列表(list)

列表 (List) 是具有相同类型的元素序列。

例如, 由数字 1, 2, 3 组成的列表表示为 [1,2,3] ,其类型是 int list

# [1; 2; 3];;
- : int list = [1; 2; 3]

在 OCaml 中,列表中的每个元素用分号 ; 分隔。将每个元素用逗号 , 

分隔的列表 [1, 2, 3] 被识别为包含元组 (1,2,3) 作为其元素的列表 [(1,2,3)] ,

因此需要注意这一点:

# [1,2,3];;
- : (int * int * int) list = [(1, 2, 3)]
# [(1,2,3)];;
- : (int * int * int) list = [(1, 2, 3)]

空列表在 OCaml 中用 [\, ]  表示,其类型是 'a list,表示多态类型:

# [];;
- : ’a list = []

在 OCaml 中,列表的所有元素必须是相同的类型。

例如,[1;true] 在 OCaml 中不是一个列表:

# [1; true];;
Error: This expression has type bool but an expression
was expected of type int

这种限制也源于静态类型系统。

例如,在具有动态类型系统 (如 Python) 的语言中,列表可以包含不同类型的值。

另外,列表是有序元素的序列。因此,下面这两个列表是不同的列表。

# [1;2;3] = [2;3;1];;
- : bool = false

0x03 列表的 head 和 tail

列表的第一个元素称为 head,除第一个元素外剩余的列表称为 tail,即头和尾。

举个例子,对于列表:

 [1; 2;3;4;5;6;7;8] \in \left \langle list \right \rangle

头是 1,尾是 2,3,4,5,6,7,8

一般来说,对于类型为 t 的列表,头的类型是 t,尾的类型是 t list 

列表的元素可以是任意类型的值,当然,每个元素的类型必须相同。

# [1;2;3;4;5];;
- : int list = [1; 2; 3; 4; 5]
# ["OCaml"; "Java"; "C"];;
- : string list = ["OCaml"; "Java"; "C"]
# [(1,"one"); (2,"two"); (3,"three")];;
- : (int * string) list =[(1, "one"); (2, "two"); (3, "three")]
# [[1;2;3];[2;3;4];[4;5;6]];;
- : int list list = [[1; 2; 3]; [2; 3; 4]; [4; 5; 6]]

最后一个例子是整数列表的列表 (int list list) 。

在这种情况下, 每个元素对应的列表可以有不同的长度。

# [[1;2;3]; [4]; []];;
- : int list list = [[1; 2; 3]; [4]; []]

列表 [1; 2; 3] 和 [4],尽管长度不同,都是整数列表;

空列表 [\, ] 是多态类型,因此也可以是整数列表。

0x04 基本列表操作符

首先是 ::(读作 cons),它可以在列表的最前面添加一个元素,从而创建一个新的列表。

# 1::[2;3];;
- : int list = [1; 2; 3]
# 1::2::3::[];;
- : int list = [1; 2; 3]

将两个列表连接在一起时,使用 @ (读作 append)。

# [1; 2] @ [3; 4; 5];;
- : int list = [1; 2; 3; 4; 5]

在编写处理列表的函数时,模式匹配经常被使用。

例如,我们可以定义函数 hd 和 tl 来获取列表的头部和尾部。

# let hd l =match l with| [] -> raise (Failure "hd is undefined")| a::b -> a;;
val hd : ’a list -> ’a = <fun>
# let tl l =match l with| [] -> raise (Failure "tl is undefined")| a::b -> b;;
val tl : ’a list -> ’a list = <fun>
# hd [1;2;3];;
- : int = 1
# tl [1;2;3];;
- : int list = [2; 3]

列表的头部和尾部对于空列表是未定义的。

如果列表 l 不是空列表,则可以将其分解为头部 a 和尾部 b

其中 hd 返回 atl 返回 b(如果列表 l 是单元素列表,则尾部 tl 是空列表)。

请注意,在上述定义中,这两个函数的返回类型是不同的。

如果省略异常处理,也可以简单地定义如下:

# let hd (a::b) = a;;
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
[]
val hd : ’a list -> ’a = <fun>
# let tl (a::b) = b;;
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
[]
val tl : ’a list -> ’a list = <fun>

在这种情况下,OCaml 提醒我们函数 hd 和 tl 没有考虑空列表的情况。

虽然这些警告信息不是编译错误,但可能在运行时引发未处理的异常,

建议事先处理所有可能的情况。举个例子,我们可以尝试编写一个函数来计算列表的长度:

# let rec length l =match l with[] -> 0|h::t -> 1 + length t;;
val length : ’a list -> int = <fun>
# length [1;2;3];;
- : int = 3

给定的列表 l 如果是空列表,则定义其长度为 0。

如果不为空,则可以将列表 l 分为头部 h 和尾部 t

此时列表 l 的长度应该等于尾部 t 的长度加 1。

根据上述定义,由于头部 h 没有被使用,可以用下划线 (_) 来表示省略:

let rec length l =match l with[] -> 0|_::t -> 1 + length t

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

📜 参考资料 

- R. Neapolitan, Foundations of Algorithms (5th ed.), Jones & Bartlett, 2015.

- T. Cormen《算法导论》(第三版),麻省理工学院出版社,2009年。

- T. Roughgarden, Algorithms Illuminated, Part 1~3, Soundlikeyourself Publishing, 2018.

- J. Kleinberg&E. Tardos, Algorithm Design, Addison Wesley, 2005.

- R. Sedgewick&K. Wayne,《算法》(第四版),Addison-Wesley,2011

- S. Dasgupta,《算法》,McGraw-Hill教育出版社,2006。

- S. Baase&A. Van Gelder, Computer Algorithms: 设计与分析简介》,Addison Wesley,2000。

- E. Horowitz,《C语言中的数据结构基础》,计算机科学出版社,1993

- S. Skiena, The Algorithm Design Manual (2nd ed.), Springer, 2008.

- A. Aho, J. Hopcroft, and J. Ullman, Design and Analysis of Algorithms, Addison-Wesley, 1974.

- M. Weiss, Data Structure and Algorithm Analysis in C (2nd ed.), Pearson, 1997.

- A. Levitin, Introduction to the Design and Analysis of Algorithms, Addison Wesley, 2003. - A. Aho, J. Hopcroft, and J. Ullman, Data Structures and Algorithms, Addison-Wesley, 1983.

- E. Horowitz, S. Sahni and S. Rajasekaran, Computer Algorithms/C++, Computer Science Press, 1997.

- R. Sedgewick, Algorithms in C: 第1-4部分(第三版),Addison-Wesley,1998

- R. Sedgewick,《C语言中的算法》。第5部分(第3版),Addison-Wesley,2002

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

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

相关文章

《单片机》期末考试复习-学习笔记总结

题型 问答题(15分)编程题(65分)编程题1(20分)编程题2(45分)设计题(20分)一、问答题 1.1.单片机概念和特点 1.2. 51单片机的中断结构 1.3.主从式多机通讯的概念及其工作原理 多机通信是指两台以上计算机之间的数据传输,主从式多机通信是多机通信系统中最简单的一种,…

SerDes介绍以及原语使用介绍(2)OSERDESE2原语仿真

文章目录 前言一、SDR模式1.1、设计代码1.2、testbench代码1.3、仿真分析 二、DDR模式下2.1、设计代码2.2、testbench代码2.3、仿真分析 三、OSERDES2级联3.1、设计代码3.2、testbench代码3.3、代码分析 前言 上文通过xilinx ug471手册对OSERDESE有了简单的了解&#xff0c;接…

PHP爬虫类的并发与多线程处理技巧

PHP爬虫类的并发与多线程处理技巧 引言&#xff1a; 随着互联网的快速发展&#xff0c;大量的数据信息存储在各种网站上&#xff0c;获取这些数据已经成为很多业务场景下的需求。而爬虫作为一种自动化获取网络信息的工具&#xff0c;被广泛应用于数据采集、搜索引擎、舆情分析…

柔性数组(flexible array)

柔性数组从C99开始支持使用 1.柔性数组的概念 概念&#xff1a; 结构体中&#xff0c;结构体最后一个元素允许是未知大小的数组&#xff0c;这就叫[柔性数组]的成员 struct S {int n;char arr[]; //数组大小未知(柔性数组成员) }; 柔性数组的特点&#xff1a; 结构体中柔性…

九、(正点原子)Linux定时器

一、Linux中断简介 1、中断号 每个中断都有一个中断号&#xff0c;通过中断号即可区分不同的中断&#xff0c;有的资料也把中断号叫做中断线。在 Linux 内核中使用一个 int 变量表示中断号。在Linux中&#xff0c;我们可以使用已经编写好的API函数来申请中断号&#xff0c;定义…

基于公有云部署wordpress

云平台选择 腾讯云 阿里云 华为云 项目部署 一、架构讲解 1.1、定义与组成 LNMP是Linux、Nginx、MySQL&#xff08;或MariaDB&#xff09;和PHP&#xff08;或Perl、Python&#xff09;的首字母缩写&#xff0c;代表在Linux系统下使用Nginx作为Web服务器&#xff0c;MySQL作为…

ai轨迹过京东m端

声明(a15018601872) 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 本…

Unity Animator 运行时修改某个动画状态的播放速度

1.添加动画参数&#xff0c;选择需要动态修改速度的动画状态 2.在属性面板种设置速度倍速参数

自然语言处理(NLP)—— 深度学习

1. 词嵌入&#xff08;Embeddings&#xff09; 1.1 词嵌入的基本概念 词嵌入&#xff08;Embeddings&#xff09;是一种将词语映射到高维空间&#xff08;比如N300维&#xff09;的技术&#xff0c;使得词语之间的欧几里得距离与它们的语义距离相关联。这意味着在这个向量空间…

windows MSVC编译安装libcurl

$ git clone https://github.com/curl/curl.git $ cd curl/winbuild依照curl/winbuild/README.md的指示&#xff0c; 启动visual studio的命令行工具&#xff0c;这里要注意别选错. 如果要编译出x64版本的libcurl&#xff0c;就用x64的命令行工具&#xff1b;如果要编译出x86…

论文学习:基于知识图谱的RAG进行客服问答

1.简介 文章名称&#xff1a; Retrieval-Augmented Generation with Knowledge Graphs for Customer Service Question Answering&#xff08;基于知识图谱的RAG进行客服问答&#xff09; 2.摘要ABSTRACT 在客户服务技术支持中&#xff0c;迅速准确地检索相关的过往问题对于有…

【干货】微信小程序免费开源项目合集

前言 2024年了&#xff0c;还有小伙伴在问微信小程序要怎么开发&#xff0c;有什么好的推荐学习项目可以参考的。今天分享一个收集了一系列在微信小程序开发中有用的工具、库、插件和资源&#xff1a;awesome-github-wechat-weapp。 开源项目介绍 它提供了丰富的资源列表&…

【每日一练】python运算符

1. 算术运算符 编写一个Python程序&#xff0c;要求用户输入两个数&#xff0c;并执行以下运算&#xff1a;加法、减法、乘法、求余、除法、以及第一个数的第二个数次方。将结果打印出来。 a input("请输入第一个数&#xff1a;") b input("请输入第二个数&…

【Java】字节数组 pcm 与 wav 格式互转 (附原理概述)

前言 最近实现了一个文字转语音的功能&#xff0c;语音引擎返回的是pcm格式的数据。需要转化成wav格式前端才能播放。本文首先会给出解决方案&#xff0c;后续会讲背后的原理。 场景 git 仓库 https://github.com/ChenghanY/pcm-wav-converter 1. pcm wav 转化工具类 入参和…

人脑计算机技术与Neuroplatform:未来计算的革命性进展

引言 想象一下&#xff0c;你在某个清晨醒来&#xff0c;准备开始一天的工作&#xff0c;而实际上你的大脑正作为一台生物计算机的核心&#xff0c;处理着大量复杂的信息。这并非科幻电影的情节&#xff0c;而是人脑计算机技术即将带来的现实。本文将深入探讨FinalSpark公司的…

明明设置允许跨域,为什么还会出现跨域请求的问题

一、问题 在微服务项目中&#xff0c;明明已经设置允许跨域访问&#xff1a; 为什么还会出现跨域请求问题&#xff1f; 二、为什么 仔细查看错误提示信息&#xff1a;When allowCredentials is true, allowedOrigins cannot contain the special value "*" since t…

pytest测试框架pytest-html插件生成HTML格式测试报告

Pytest提供了丰富的插件来扩展其功能&#xff0c;pytest-html插件帮助我们生成HTML格式的测试报告&#xff0c;为我们提供直观、有效的测试结果展示。 为了使用 pytest-html&#xff0c;需要满足以下条件&#xff1a; Python 3.6 或更高版本 pytest-html安装 使用pip命令安…

【Linux】服务器被work32病毒入侵CPU占用99%

文章目录 一、问题发现二、问题解决2.1 清楚病毒2.2 开启防火墙2.3 修改SSH端口2.4 仅使用凭据登录&#xff08;可选&#xff09; 一、问题发现 我的一台海外服务器&#xff0c;一直只运行一项服务&#xff08;你懂的&#xff09;&#xff0c;但是前不久我发现CPU占用99%。没在…

【漏洞复现】宏景HCM人力资源信息管理系统——任意文件读取漏洞

声明&#xff1a;本文档或演示材料仅供教育和教学目的使用&#xff0c;任何个人或组织使用本文档中的信息进行非法活动&#xff0c;均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现测试工具 漏洞描述 宏景HCM人力资源信息管理系统是一款全面覆盖人力资源管理各模块…

“Hello, World!“ 历史由来

布莱恩W.克尼汉&#xff08;Brian W. Kernighan&#xff09;—— Unix 和 C 语言背后的巨人 布莱恩W.克尼汉在 1942 年出生在加拿大多伦多&#xff0c;他在普林斯顿大学取得了电气工程的博士学位&#xff0c;2000 年之后取得普林斯顿大学计算机科学的教授教职。 1973 年&#…