【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.mzph.cn/news/862142.shtml

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

相关文章

IP中转是什么?IP中转会导致网速下降吗

在互联网通信中&#xff0c;IP中转是一个重要的概念&#xff0c;它涉及到数据包的路由和转发。但很多人对于IP中转及其对网络速度的影响并不十分了解。本文将详细解释IP中转的含义&#xff0c;并探讨它是否会导致网速下降。 IP中转是什么&#xff1f; IP中转&#xff0c;也称…

8.作用域与函数

1.局部变量与全局变量: 局部:在函数体或局部范围内声明的变量称为局部变量,仅在局部作用域内有效. 全局:在函数之外或全局范围内声明的变量,允许在函数内部和外部访问.不允许在函数内部修改. 2.global:用于在函数内部访问和修改全局作用域中的变量,通过在函数内部使用global关键…

沉淀强化镍基合金660大螺丝的物理性能

沉淀强化镍基合金660大螺丝&#xff0c;是一种高性能的工程材料&#xff0c;其在极端环境中展现了优异的稳定性和耐用性。以下&#xff0c;我们将深入解析其主要的物理性能。 首先&#xff0c;该合金螺丝的密度为7.99g/cm&#xff0c;这意味着它具有较高的质量密度&#xff0c;…

MethodArgumentNotValidException

MethodArgumentNotValidException 是 Spring 框架中用于处理方法参数验证失败时抛出的异常。通常在使用 Spring MVC 或 Spring Boot 时&#xff0c;当请求体中的数据未通过验证注解&#xff08;如 NotNull, Size, Min, Max 等&#xff09;的检查时&#xff0c;会抛出此异常。 …

lodash _.template()方法的使用

背景&#xff1a; 使用_.template()生成对应数据的对应html代码 核心代码&#xff1a; //定义一个变量来装finalHtml var finalHtml //1.模版 compiled _.template([<span class"${clazz}" index"${index}" style"bac…

APM Profile 在系统可观测体系中的应用

引言 应用程序性能分析&#xff08;Application Performance Management&#xff0c;APM&#xff09;是一个广泛的概念&#xff0c;涉及应用程序运行时各种性能指标的监测、诊断和优化。在可观测体系建设中&#xff0c;APM 是保障系统业务运行性能的关键技术&#xff0c;确保用…

Tomcat WEB站点部署

目录 1、使用war包部署web站点 2、自定义默认网站目录 3、部署开源站点&#xff08;jspgou商城&#xff09; 对主机192.168.226.22操作 对主机192.168.226.20操作 上线的代码有两种方式&#xff1a; 第一种方式是直接将程序目录放在webapps目录下面&#xff0c;这种方式…

多协议网关BL110钡铼6路RS485转MQTT协议云网关

在工业自动化的现代化进程中&#xff0c;物联网技术的应用日益广泛&#xff0c;特别是工业物联网网关作为连接传感器、控制器和云端平台的关键枢纽&#xff0c;发挥着至关重要的作用。BL110钡铼多协议网关作为一款专为工业环境设计的先进设备&#xff0c;不仅支持多种下行采集协…

【Vue.js】 Mixin 局部混入与全局混入的介绍和使用总结以及优缺点分析

1. Vue.js Mixin 概述 1.1 Mixin 的定义与作用 Mixin 在 Vue.js 中是一种灵活的组件复用机制。它允许我们将多个组件之间的共通功能抽象出来&#xff0c;形成一个混入对象。这样&#xff0c;我们就可以避免在多个组件中重复编写相同的代码&#xff0c;提高代码的复用性和可维…

【代码随想录】【算法训练营】【第51天】 [115]不同的子序列 [583]两个字符串的删除操作 [72]编辑距离

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 LeetCode。 day 51&#xff0c;周四&#xff0c;又是不能坚持的一天~ 题目详情 [115] 不同的子序列 题目描述 115 不同的子序列 解题思路 前提&#xff1a; 思路&#xff1a; 重点&#xff1a; 代码实现 …

【chatgpt】利用遗传编程(GP)生成编译原理代码

利用遗传编程&#xff08;GP&#xff09;生成编译原理代码是一种自动化编程技术&#xff0c;通过进化算法寻找解决特定问题的最优代码。以下是如何利用GP生成编译原理代码的示例步骤&#xff1a; 1. 定义问题 确定需要解决的编译原理问题&#xff0c;如词法分析器、语法分析器…

windows下修改Jar包内容的两种方式

windows下修改Jar包内容的两种方式 背景第一种&#xff1a;解压工具第二种&#xff1a;Jar命令附Jar命令用法基本用法常见选项示例1&#xff1a;创建一个简单的 JAR 文件示例2&#xff1a;创建包含清单文件的 JAR 文件示例3&#xff1a;列出 JAR 文件的内容示例4&#xff1a;提…

数据库物理结构设计-定义数据库模式结构(概念模式、用户外模式、内模式)、定义数据库、物理结构设计策略

一、引言 如何基于具体的DBMS产品&#xff0c;为数据库逻辑结构设计的结果&#xff0c;即关系数据库模式&#xff0c;制定适合应用要求的物理结构 1、在设计数据库物理结构前&#xff0c;数据库设计人员首先 要充分了解所用的DBMS产品的功能、性能和特点&#xff0c;包括提供…

【Unity】数据持久化--PlayerPrefs

1、PlayerPrefs是什么 是unity提供的可以用于存储读取玩家数据的公共类 2、存储相关 2.1 PlayerPrefs的数据存储类似于键值对存储一个键对应一个值 提供了存储3种数据的方法int float string 键: string类型 值: int float string对应3种API PlayerPrefs.SetInt("myAge…

慧科新闻搜索研究数据库的使用指南及个人获取途径

《慧科新闻搜索研究数据库》WiseSearch由慧科讯业有限公司出品。WiseSearch是具有新闻搜索/浏览、对比分析等功能的一站式新闻搜索平台&#xff1b;内容包括1200种报刊和8000 网站的新闻资讯&#xff0c;平面媒体涵盖全国综合大报、党委机关报、都市报、行业报刊媒体&#xff0…

算法08 广/宽度优先搜索及相关问题详解

这是《C算法宝典》算法篇的第08节文章啦~ 如果你之前没有太多C基础&#xff0c;请点击&#x1f449;专栏&#xff1a;C语法入门&#xff0c;如果你C语法基础已经炉火纯青&#xff0c;则可以进阶算法&#x1f449;专栏&#xff1a;算法知识和数据结构&#x1f449;专栏&#xff…

数据结构与算法高频面试题

初级面试题及详细解答 当涉及到数据结构与算法的初级面试题时&#xff0c;通常涉及基本的数据结构操作、算法复杂度分析和基本算法的应用。 1. 什么是数组&#xff1f;数组和链表有什么区别&#xff1f; 解答&#xff1a; 数组&#xff1a;是一种线性数据结构&#xff0c;用…

SKYDROID-C12—— 让美景近在眼前

C12是一款小型高清双光吊舱&#xff0c;使用新一代影像芯片&#xff0c;搭配高清无畸变摄像头&#xff0c;有效像素达到500万&#xff0c;拥有强悍的2K视频录制和拍照能力&#xff0c;支持数字变倍&#xff0c;随时随地捕捉清晰的图像&#xff0c;让远处美景近在眼前。

mysql 提取拼音时一个重复字导致的错误

在提取拼音时&#xff0c;一直报错&#xff0c;提示&#xff1a;Result consisted of more than one row 最后发现是礼这个字导致的&#xff0c;发现有两个写法不同&#xff0c;但是mysql识别为同一个字导致的

el-upload+python fastAPI实现上传文件

el-upload通过action指定后端接口&#xff0c;并通过name指定传输的文件包裹在什么变量名中 <el-uploadclass"upload-demo"dragaction"https://ai.zscampus.com/toy/upload"multiplename"fileList":limit"10"accept".xlsx, .x…