应用逻辑:haskell生成有理数集合

本文介绍了一个使用Haskell编程语言生成全部有理数集合无限序列的方法,通过核心函数nextrational生成整数对,进而转换为有理数,确保序列覆盖所有有理数且无重复。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在上应用逻辑的课程,老师布置了一道题:

生成全部的有理数集合的无限序列,也就是所有的有理数都要包含在这个集合中,并且还要求没有重复的未化简的形式

看了两天haskell,另外借鉴了师兄去年的java代码,然后自己用haskell实现了一下,后面再附带上:代码解释+数学证明

haskell代码

mappend f []=[]					//构建工具,将指定函数f应用在指定list上
mappend f (x:xs)=f x ++mappend f xs
builds a f=set where set=a:mappend f set//构建一个无限序列的mappend工具

nextrational [a,b]=[[a,a+b],[a+b,b]]//用于生成所有的正有理数(以整数对的形式出现,a/b)
rational=builds [1,1] nextrational//正有理数的整数对序列
//结果:[[1,1],[1,2],[2,1],[1,3],[3,2],[2,3],[3,1],[1,4],[4,3],[3,5]...]
list2frac [a,b]=a/b				//将整数对转换成有理数
pq=map list2frac rational			//对整数对列表应用转换函数
p2pn []=[]
p2pn (x:xs)=[x]++[-x]++ (p2pn xs)		//将正有理数序列转换为正负有理数序列
rationals=[0]++p2pn pq				//所有有理数

代码解释

1.mappend是一个简单的映射,可以把函数应用到list上,list每个成员进行处理,和map的区别就是他是尾递归(foldl和foldr的区别也类似map和mappend的区别),下面放上这两种不同的map

//尾递归
mappend f []=[]
mappend f (x:xs)=f x ++mappend f xs
//递归
map f [] = []
map f (x:xs) = f x : map f xs

2.builds改造了下mappend,使其能够作用在一个初始值上从而产生无限序列,这个看着代码理解应该不难
3.nextrational [a,b]=[[a,a+b],[a+b,b]]这个就属于核心的函数了,我们通过把一个整数对映射出两个新的整数对的方式来发展我们的序列()
注:a代表着分子,b代表着分母,一开始的[a,b]是[1,1],不断对list中的新成员应用函数nextrational、无限发展,在后续步骤中只要对这个整数对序列一处理就可以得到a/b这个有理数
4.rational=builds [1,1] nextrational使用我们上面构建的工具和函数生成 代表着正有理数的整数对序列
的到的rational结果:[[1,1],[1,2],[2,1],[1,3],[3,2],[2,3],[3,1],[1,4],[4,3],[3,5]…]
对这个结果稍加处理就可以得到正有理数
5.使用一些函数对正整数对序列进行处理
list2frac [a,b]=a/b 函数作用:将一个整数对转换成有理数
pq=map list2frac rational 对整数对的序列应用转换函数
6.pq代表所有的正有理数,我们对其添0和添负
p2pn []=[]
p2pn (x:xs)=[x]++[-x]++ (p2pn xs) 将正有理数序列转换为正负有理数序列
rationals=[0]++(p2pn pq ) 得到所有有理数

//取前20个 take 20 rationals
[0.0,1.0,-1.0,0.5,-0.5,2.0,-2.0,
0.3333333333333333,-0.3333333333333333,1.5,-1.5,
0.6666666666666666,-0.6666666666666666,3.0,-3.0,0.25,-0.25,
1.3333333333333333,-1.3333333333333333,0.6]
//再看看前20个正整数对 take 20 rational
[[1,1],[1,2],[2,1],[1,3],[3,2],[2,3],[3,1],[1,4]
,[4,3],[3,5],[5,2],[2,5],[5,3],[3,4],[4,1],[1,5]
,[5,4],[4,7],[7,3],[3,8]]

数学证明

需要证明:
1.能够涵盖所有的有理数
2.不会出现重复
证明涵盖了所有有理数并且不会重复出现同值的有理数
OK,就这么多,因为学艺不精,有错误指出欢迎大佬纠正

### 有理数集合的可数性证明 #### 定义与背景 有理数集合 \(\mathbb{Q}\) 是指所有可以表示为分数形式 \( \frac{p}{q} \),其中 \( p, q \in \mathbb{Z}, q \neq 0\) 的数构成的集合[^1]。 #### 可数性的定义 如果一个无限集合能够与其子集自然数集 \(\mathbb{N}\) 建立双射(即一一对应),则这个集合被称为可数无穷集合。为了证明有理数集合是可数的,需要找到一种方式来枚举所有的有理数,使得每一个有理数都能被唯一地映射到一个自然数上。 #### 构造方法 考虑如下表格排列法: | | q=1 | q=2 | q=3 | |----|---------|----------|-----------| | **p=0** | 0/1(0) | | | | **p=1** | 1/1(1) | 1/2(2) | | | **p=-1**| -1/1(-1)| -1/2(-2)| | | ... | | | | 此表中每一项代表一个有理数,按照分母 \(q\) 和分子 \(p\) 排列。注意到正负号也会影响最终的结果。通过蛇形遍历上述矩阵中的元素,可以从左下角向右上方逐步访问每个格子内的有理数,并赋予其唯一的编号,形成从自然数到有理数之间的一一对应关系。 ```python def enumerate_rationals(): rationals = [] n = 0 while True: for p in range(-n, n + 1): for q in [abs(p), abs(p)+1]: if gcd(abs(p), q) == 1 and q != 0: # Ensure simplest form yield f"{p}/{q}" n += 1 ``` 这段 Python 代码展示了如何生成简化后的有理数序列。这里 `gcd` 函数用于求最大公约数以确保得到最简分数形式。 因此,通过对有理数进行适当排序并建立与自然数之间的单射函数,成功证明了有理数集合是可以计数的。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值