当前位置: 首页 > article >正文

面向程序员的Lean 4教程(2) - 数组和列表

面向程序员的Lean 4教程(2) - 数组和列表

上一节我们介绍了Lean4的基本语法,因为大部分程序员都有一定的编程基础,所以并没有介绍过细。这一节我们介绍Lean4中的线性表结构:数组和列表,顺带复习一下上一节的流程控制等内容。

数组

创建数组

Lean4中的数组可以用#[]来进行初始化,也可以用Array.mk来创建。数组的元素类型可以是任意类型,但是所有元素的类型必须相同。

  let a1 : Array Nat := #[1, 2, 3, 4, 5]let a2 : Array Int := Array.mk [1, 2, 3, 4, 5]IO.println a1IO.println a2

输出如下:

#[1, 2, 3, 4, 5]
#[1, 2, 3, 4, 5]

访问数组元素

Lean4中的数组元素可以通过a[i]来访问,其中a是数组,i是索引。

  IO.println a1[0]IO.println a2[1]

我们也可以通过Array.get来访问数组元素。

如果想直接获取值,我们可以使用get!,如果可能为空,我们要使用get?

  IO.println a1.get! 0IO.println a2.get? 1

get?返回一个Option类型,我们可以通过match来处理。

  match a1.get? 10 with| none => IO.println "Not found"| some v => IO.println v

修改数组元素

Lean4中的数组元素是只读的,我们不能直接修改数组元素。如果想修改数组元素,我们可以使用Array.set!,它会返回一个新的数组。

  let a4 : Array Nat := Array.set! a1 0 10IO.println a4

获取数组长度

Lean4中的数组长度可以通过Array.size来获取:

  IO.println (Array.size a4)IO.println (a4.size)

拼接数组

Lean4中的数组可以通过Array.append来拼接:

  let a5 := Array.append a1 a4IO.println a5

输出如下:

#[1, 2, 3, 4, 5, 10, 2, 3, 4, 5]

数组切片

Lean4中的数组可以通过Array.extract来切片:

  let a6 := Array.extract a5 1 4IO.println a6

输出如下:

#[2, 3, 4]

数组反转

Lean4中的数组可以通过Array.reverse来反转:

  let a7 := Array.reverse a5IO.println a7

输出如下:

#[5, 4, 3, 2, 10, 5, 4, 3, 2, 1]

数组排序

Lean4中的数组可以通过Array.qsort来排序:

  let a8 := Array.qsort a5 (fun x y => x < y)IO.println a8

输出如下:

#[1, 2, 2, 3, 3, 4, 4, 5, 5, 10]

fun定义了一个匿名函数,x < y是函数体。

但是这样的写法不高级,在Lean4中我们可以使用洞来简化:

  let a8 := Array.qsort a5 (. < .)IO.println a8

fun这样的关键字省了,形式参数用.来表示,只突出了最重要关系判断的部分。是不是很高级?:)

查找数组是否包含某个元素

Lean4中的数组可以通过Array.contains来查找是否包含某个元素:

  let b2 := Array.contains a8 10IO.println b2

输出为true

查找符合条件的元素

如果只想找到一个符合条件的元素,我们可以使用Array.find?

  let a10 := Array.find? (. > 3) a8IO.println a10

输出为some 4

如果想找到所有符合条件的元素,我们可以使用Array.filter

  let a11 := Array.filter (. > 3) a8IO.println a11

输出为#[4, 4, 5, 5, 10]

像栈一样操作数组

Lean4中的数组可以通过Array.push来像栈一样操作:

  let a11 := a10.push 100IO.println a11

输出如下:

#[8, 10, 2, 4, 6, 8, 10, 12, 14, 16, 18, 100]

然后我们可以通过Array.pop来弹出栈顶元素,这样数组就变成了原来的数组:

  let a12 := a11.popIO.println a12

输出如下:

#[8, 10, 2, 4, 6, 8, 10, 12, 14, 16, 18]

列表

数组一般是在内存中连续存储的,而列表是在内存中不连续存储的。

可以通过[]来创建列表:

  let l1 : List Nat := [1, 2, 3, 4, 5]IO.println l1

输出如下:

[1, 2, 3, 4, 5]

除此之外,我们还可以使用List.range来创建:

  let l2 := List.range 10IO.println l2

输出如下:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

列表的连接

Lean4中的列表可以通过List.append来连接,但是更常用的是++运算符:

  let l3 := l1 ++ l2IO.println l3

输出如下:

[1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

获取列表长度

Lean4中的列表长度可以通过List.length来获取:

  IO.println (List.length l3)IO.println (l3.length)

输出如下:

15
15

列表的反转

同数组一样,Lean4中的列表可以通过List.reverse来反转:

  let l4 := l3.reverseIO.println l4

输出如下:

[9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 5, 4, 3, 2, 1]

列表的遍历

按命令式编程的思维,传统方式就是用for循环来遍历列表:

  for x in l5 doIO.println x

用函数式编程的方式,我们可以使用map来遍历列表。比如生成一个新的列表,每个元素都是原来的元素的2倍:

  let l5 := l3.map ( . * 2)IO.println l5

列表的切片

Lean4中的列表可以通过List.take来获取前n个元素:

  let l6 := l5.take 3IO.println l6

输出如下:

[2, 4, 6]

Lean4中的列表可以通过List.drop来删除前n个元素:

  let l7 := l5.drop 3IO.println l7

输出如下:

[8, 10, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

列表的折叠

折叠是函数式编程中的一个重要概念,它可以将一个列表中的元素通过某种规则合并成一个值。

最常用的折叠情况就是求和:

  let l8 := l7.foldl (. + .) 0IO.println l8

输出为108

我们同样可以使用foldr来从右边开始折叠,这次我们求积。但是我们的列表里有0,所以我们先用filter过滤掉0:

  let l9 := l7.filter (. > 0)IO.println (l9.foldr (. * .) 1)

列表转换成数组

Lean4中的列表可以通过List.toArray来转换成数组:

  let a10 := l9.toArrayIO.println a10

输出如下:

#[8, 10, 2, 4, 6, 8, 10, 12, 14, 16, 18]

列表去重

Lean4中的列表可以通过List.eraseDup来去重,也就是去掉重复的元素:

  let l10 := l5.eraseDupsIO.println l10

输出如下:

[2, 4, 6, 8, 10, 0, 12, 14, 16, 18]

列表的量词

Lean4中的列表可以通过List.all来判断是否所有元素都满足某个条件,例:

  let b3 := l5.all (. > 0)IO.println b3

我们知道,l5中含有元素0,所以输出为false

Lean4中的列表还可以通过List.any来判断是否有元素满足某个条件:

  let b4 := l5.any (. > 0)IO.println b4

因为除了0以外,l5中的所有元素都大于0,所以满足条件,输出为true

给列表的头部添加元素

可以使用构造符号::来给列表的头部添加元素,当然,是生成新的列表:

  let l11 := 100 :: l5IO.println l11

输出如下:

[100, 2, 4, 6, 8, 10, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

在头部添加元素的时间复杂度是O(1)。

在尾部添加元素的时间复杂度是O(n),就是我们之前介绍的++运算符。

可变的数组和列表

Lean4中的数组和列表是不可变的,如果想要可变的数组和列表,我们可以使用IO.Ref
注意,从IO.Ref获取值时,我们需要使用,不要写成:=

    let mut r1IO.mkRef #[1, 2, 3, 4, 5]let mut r2IO.mkRef [1, 2, 3, 4, 5]

然后我们可以通过IO.Ref.get来获取值,通过IO.Ref.set来设置值。

  let mut r1IO.mkRef #[1, 2, 3, 4, 5]let arr1r1.getIO.println arr1r1.set (arr1.push 6)IO.println (r1.get)

输出如下:

#[1, 2, 3, 4, 5]
#[1, 2, 3, 4, 5, 6]

对于列表,我们也是同样做法:

  let mut r2IO.mkRef [1, 2, 3, 4, 5]let arr2r2.getIO.println arr2r2.set (arr2 ++ [6])IO.println (r2.get)

输出如下:

[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6]

小练习

下面我们做几个小练习,看看大家有没有适应Lean4的编程方式。

  1. 将一个Nat类型的列表转换成Int类型的列表

例:

  let l13: List Nat := [1, 2, 3, 4, 5]let l14 := l13.map Int.ofNatIO.println l14

Int.ofNat是将Nat类型转换成Int类型的函数,所以我们不需要再定义一个新的函数,直接调用它就可以了。

  1. 由于List只能顺序访问,我们将其转化成数组,然后排序,最后再转化回List。

例:

def sortList (lst : List Nat) : List Nat :=let arr := List.toArray lst  -- 将列表转换为数组let sortedArr := Array.qsort arr (. < .)   -- 对数组进行排序Array.toList sortedArr  -- 将排序后的数组转换回列表
  1. 实现一个函数,遍历二维数组

最简单的方法就是使用两个for循环:

def traverse2DArray (arr : Array (Array Nat)) : IO Unit := dofor row in arr dofor elem in row doIO.print s!"{elem} "IO.println ""

当然也可以采用别的函数式的方法,或者递归的方法。

小结

本节我们不厌其烦地介绍了很多数组和列表的操作,在让大家熟悉这两种数据结构的同时,也是让大家进一步熟悉Lean4的基本编程方式。我们后面会继续深入,现在大家可以先练习一下用Lean4来写一些简单的代码。

相关文章:

面向程序员的Lean 4教程(2) - 数组和列表

面向程序员的Lean 4教程(2) - 数组和列表 上一节我们介绍了Lean4的基本语法&#xff0c;因为大部分程序员都有一定的编程基础&#xff0c;所以并没有介绍过细。这一节我们介绍Lean4中的线性表结构&#xff1a;数组和列表&#xff0c;顺带复习一下上一节的流程控制等内容。 数…...

【C++高并发服务器WebServer】-7:共享内存

本文目录 一、共享内存1.1 shmget函数1.2 shmat1.3 shmdt1.4 shmctl1.5 ftok1.6 共享内存和内存映射的关联1.7 小demo 二、共享内存操作命令 一、共享内存 共享内存允许两个或者多个进程共享物理内存的同一块区域&#xff08;通常被称为段&#xff09;。由于一个共享内存段会称…...

【力扣Hot 100】链表1

1. 相交链表 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交**&#xff1a;** !https://assets.leetcode-cn.com/aliyun-lc-upload/uplo…...

稀土抗菌剂:提升产品质量,保障公共健康

随着全球对抗菌技术需求的不断增长&#xff0c;传统的抗菌剂逐渐暴露出其局限性&#xff0c;包括耐药性、环境污染及副作用等问题。在此背景下&#xff0c;稀土抗菌剂作为一种新兴的抗菌材料&#xff0c;凭借其卓越的抗菌性能、环保特性以及应用多样性&#xff0c;正在成为各行…...

机器学习11-学习路径推荐

机器学习11-学习路径推荐 本文希望摒除AI学习商业宣传要素&#xff0c;推荐一条极简的AI学习路线&#xff01;推荐内容均为在线免费内容&#xff0c;如果有条件可以咨询专业的培训机构&#xff01; 文章目录 机器学习11-学习路径推荐[toc] 1-AI培训路线第一阶段 Python-人工智能…...

postgresql根据主键ID字段分批删除表数据

生产环境针对大表的处理相对比较麻烦。 方案1、直接truncate&#xff0c;可能会遇到系统卡主的情况&#xff0c;因为truncate的过程中会对表进行加锁&#xff0c;会导致数据不能正常的写入 方案2、创建一个同结构的表结构&#xff0c;rename旧表&#xff0c;不停业务rename表担…...

《边界感知的分而治之方法:基于扩散模型的无监督阴影去除解决方案》学习笔记

paper&#xff1a;Boundary-Aware Divide and Conquer: A Diffusion-Based Solution for Unsupervised Shadow Removal 目录 摘要 1、介绍 2、相关工作 2.1 阴影去除 2.2 去噪扩散概率模型&#xff08;Denoising Diffusion Probabilistic Models, DDPM&#xff09; 3、方…...

java后端之事务管理

Transactional注解&#xff1a;作用于业务层的方法、类、接口上&#xff0c;将当前方法交给spring进行事务管理&#xff0c;执行前开启事务&#xff0c;成功执行则提交事务&#xff0c;执行异常回滚事务 spring事务管理日志&#xff1a; 默认情况下&#xff0c;只有出现Runti…...

深入浅出 SQLSugar:快速掌握高效 .NET ORM 框架

SQLSugar 是一个高效、易用的 .NET ORM 框架&#xff0c;支持多种数据库&#xff08;如 SQL Server、MySQL、PostgreSQL 等&#xff09;。它提供了丰富的功能&#xff0c;包括 CRUD 操作、事务管理、动态表名、多表联查等&#xff0c;开发者可以通过简单的链式操作实现复杂的数…...

数据结构——概念与时间空间复杂度

目录 前言 一相关概念 1什么是数据结构 2什么是算法 二算法效率 1如何衡量算法效率的好坏 2算法的复杂度 三时间复杂度 1时间复杂度表示 2计算时间复杂度 2.1题一 2.2题二 2.3题三 2.4题四 2.5题五 2.6题六 2.7题七 2.8题八 四空间复杂度 1题一 2题二 3…...

浅谈在AI时代GIS的发展方向和建议

在AI时代&#xff0c;GIS&#xff08;地理信息系统&#xff09;的发展正经历着深刻的变革&#xff0c;随着人工智能技术的进步&#xff0c;GIS不再仅仅是传统的地图和空间数据处理工具&#xff0c;而是向更加智能化、自动化、精准化的方向发展。作为一名GIS开发工程师&#xff…...

牛客周赛 Round 78 A-C

A.时间表查询&#xff01; 链接&#xff1a;https://ac.nowcoder.com/acm/contest/100671/A 来源&#xff1a;牛客网 题目描述 今天是2025年1月25日&#xff0c;今年的六场牛客寒假算法基础集训营中&#xff0c;前两场比赛已经依次于 20250121、20250123 举行&#xff1b;而…...

Java I/O 流介绍

Java学习资料 Java学习资料 Java学习资料 一、引言 在 Java 编程中&#xff0c;I/O&#xff08;Input/Output&#xff09;流是处理输入和输出操作的核心机制。它允许程序与外部设备&#xff08;如文件、网络连接、键盘、显示器等&#xff09;进行数据交互。通过使用 I/O 流&…...

linux 内核学习方向以及职位

### 学习路径 1. 基础阶段&#xff1a; - C语言高级特性 - 指针和内存管理 - 数据结构实现 - 位操作 - 多线程编程 - Linux系统编程 - 文件I/O操作 - 进程管理 - 信号处理 - IPC机制 - Socket编程 - 必备知识 - 操作系统原理 - 计算机体系结构 - …...

HTML-新浪新闻-实现标题-样式1

用css进行样式控制 css引入方式&#xff1a; --行内样式&#xff1a;写在标签的style属性中&#xff08;不推荐&#xff09; --内嵌样式&#xff1a;写在style标签中&#xff08;可以写在页面任何位置&#xff0c;但通常约定写在head标签中&#xff09; --外联样式&#xf…...

【电磁兼容】CE 传导骚扰

一。是什么&#xff1f; 传导骚扰是指电气或电子设备产生的不需要的电磁能量&#xff0c;这些能量通过导线或其他金属路径传播到其他设备或者系统中。这种类型的干扰通常发生在同一电源线路连接的不同装置之间&#xff0c;或者是共享相同布线系统的组件间。 传导骚扰可以分为两…...

能说说MyBatis的工作原理吗?

大家好&#xff0c;我是锋哥。今天分享关于【Redis为什么这么快?】面试题。希望对大家有帮助&#xff1b; 能说说MyBatis的工作原理吗&#xff1f; MyBatis 是一款流行的持久层框架&#xff0c;它通过简化数据库操作&#xff0c;帮助开发者更高效地与数据库进行交互。MyBatis…...

詳細講一下RN(React Native)中的列表組件FlatList和SectionList

1. FlatList 基礎使用 import React from react; import { View, Text, FlatList, StyleSheet } from react-native;export const SimpleListDemo: React.FC () > {// 1. 準備數據const data [{ id: 1, title: 項目 1 },{ id: 2, title: 項目 2 },{ id: 3, title: 項目 3…...

LabVIEW进行可靠性测试时有哪些常见的问题

在进行LabVIEW开发和测试时&#xff0c;尤其是用于可靠性测试&#xff0c;可能会遇到一些常见的问题。以下是一些常见问题及其解决方法&#xff1a; 1. 数据采集卡与硬件兼容性问题 问题描述&#xff1a;某些数据采集卡&#xff08;DAQ&#xff09;与硬件设备的兼容性问题可能…...

MFC程序设计(四)窗口创建机制

钩子函数 钩子属于win32技术&#xff0c;具有优先勾取消息的权利&#xff1a;当一个消息产生时&#xff0c;钩子勾取消息进行处理&#xff0c;然后消息才送回程序 接下来以一个勾取窗口创建消息的钩子为例进行讲解 钩子类型有键盘钩子&#xff0c;鼠标钩子&#xff0c;WH_CBT…...

【JavaEE进阶】Spring留言板实现

目录 &#x1f38d;预期结果 &#x1f340;前端代码 &#x1f384;约定前后端交互接口 &#x1f6a9;需求分析 &#x1f6a9;接口定义 &#x1f333;实现服务器端代码 &#x1f6a9;lombok介绍 &#x1f6a9;代码实现 &#x1f334;运行测试 &#x1f384;前端代码实…...

Unity开发一个单人FPS游戏的教程总结

这个系列的前几篇文章介绍了如何从头开始用Unity开发一个FPS游戏&#xff0c;感兴趣的朋友可以回顾一下。这个系列的文章如下&#xff1a; Unity开发一个FPS游戏_unity 模仿开发fps 游戏-CSDN博客 Unity开发一个FPS游戏之二_unity 模仿开发fps 游戏-CSDN博客 Unity开发一个F…...

论文速读|Is Cosine-Similarity of Embeddings Really About Similarity?WWW24

论文地址&#xff1a; https://arxiv.org/abs/2403.05440 https://dl.acm.org/doi/abs/10.1145/3589335.3651526 bib引用&#xff1a; inproceedings{Steck_2024, series{WWW ’24},title{Is Cosine-Similarity of Embeddings Really About Similarity?},url{http://dx.doi.o…...

71.在 Vue 3 中使用 OpenLayers 实现按住 Shift 拖拽、旋转和缩放效果

前言 在前端开发中&#xff0c;地图功能是一个常见的需求。OpenLayers 是一个强大的开源地图库&#xff0c;支持多种地图源和交互操作。本文将介绍如何在 Vue 3 中集成 OpenLayers&#xff0c;并实现按住 Shift 键拖拽、旋转和缩放地图的效果。 实现效果 按住 Shift 键&#…...

PyQt6医疗多模态大语言模型(MLLM)实用系统框架构建初探(上.文章部分)

一、引言 1.1 研究背景与意义 在数字化时代,医疗行业正经历着深刻的变革,智能化技术的应用为其带来了前所未有的发展机遇。随着医疗数据的指数级增长,传统的医疗诊断和治疗方式逐渐难以满足现代医疗的需求。据统计,全球医疗数据量预计每年以 48% 的速度增长,到 2025 年将…...

250125-package

1. 定义 包就是文件夹&#xff0c;作用是在大型项目中&#xff0c;避免不同人的编写的java文件出现同名进而导致报错&#xff1b;想象一个场景&#xff0c;在一个根目录中&#xff0c;每一个人都有自己的一个java文件夹&#xff0c;他可以将自己编写的文件放在该文件夹里&…...

左右互博02-unidbg主动调用外层so函数

unidbg 代码 ` package com.koohairev.demo;import com.github.unidbg.AndroidEmulator; import com.github.unidbg.LibraryResolver; import com.github.unidbg.Module; import com.github.unidbg.Symbol; import com.github.unidbg.arm.backend.DynarmicFactory; import com.…...

FastExcel的使用

前言 FastExcel 是一款基于 Java 的开源库&#xff0c;旨在提供快速、简洁且能解决大文件内存溢出问题的 Excel 处理工具。它兼容 EasyExcel&#xff0c;提供性能优化、bug 修复&#xff0c;并新增了如读取指定行数和将 Excel 转换为 PDF 的功能。 FastExcel 的主要功能 高性…...

均值(信息学奥赛一本通-1060)

【题目描述】 给出一组样本数据&#xff0c;包含n个浮点数&#xff0c;计算其均值&#xff0c;精确到小数点后4位。 【输入】 输入有两行&#xff0c;第一行包含一个整数n&#xff08;n小于100&#xff09;&#xff0c;代表样本容量&#xff1b;第二行包含n个绝对值不超过1000的…...

Redis实战(黑马点评)——关于缓存(缓存更新策略、缓存穿透、缓存雪崩、缓存击穿、Redis工具)

redis实现查询缓存的业务逻辑 service层实现 Overridepublic Result queryById(Long id) {String key CACHE_SHOP_KEY id;// 现查询redis内有没有数据String shopJson (String) redisTemplate.opsForValue().get(key);if(StrUtil.isNotBlank(shopJson)){ // 如果redis的数…...