精神病人思维广

想得太多,读得太少

浅谈 Intersection Types

序一:本来打算写“浅谈 Intersection Types 和 Union Types”的,后来考虑到前者的篇幅已经有点长了,就砍成了“浅谈 Intersection Types”,后半部分以后再谈。

序二:网上其实有挺多关于 intersection types (和 union types)的文章了,且大部分是以 TypeScript 为宿主语言进行说明的。不过那些文章比较侧重这两种类型在 TypeScript 中的使用方式,对这以外的知识鲜有说明,本文旨在弥补这一不足。

本文大量参考了《Programming with Intersection Types and Bounded Polymorphism》《Row and Bounded Polymorphism via Disjoint Polymorphism》,或者直接说翻译吧,更贴切些,毕竟也没有太多自己的原创研究。

Intersection 类型

Intsersection 类型太长,后文一律简称 I 类型。

相信大家在生活中经常会看到 “既要……,且要……,还要……” 这样的句式,I 类型正是又一例证。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
interface Fly {
void fly();
}
interface Swim {
void swim();
}
interface Run {
void run();
}


class C<T extends Fly & Swim & Run> {
T omni;
void test() {
omni.fly();
omni.swim();
omni.run();

omni.run();
omni.fly();
}
}

如上的 Java 代码, T extends Fly & Swim & Run 部分引入的类型 T 本质上就是一个 I 类型 ,意即 T “既要能飞,且要会游,还要善跑”。可以看出,在函数 test 函数中,T 类型的 omni 确实展现出了惊动自然的能力,先后表演了飞翔、潜泳、疾驰,最后连跑带飞的溜了。刚开始介绍,不要嫌我啰嗦:“所以说,正因为 T 这个类型兼具了 FlySwimRun 三个类型的所有能力,定义在这三个类型里的函数才都可以被调用;如果这三个类型有成员的话,自然也都是可以被访问的。”

我们不禁要问,这样的传奇真的存在吗?还好,在代码中我们可以直接无中生有,例如

1
2
3
4
5
class Omnipotence implements Fly, Swim, Run {
void swim() { /* do something */ };
void run() { /* do something */ };
void fly() { /* do something */ };
}

便硬生生地造了一个满足要求的类型 Omnipotence,对造物主来说真是小事一桩。

言归正传。下文中我们使用 & 作为 I 类型的类型构造器。& 接受两个类型(其实一组类型也可以,但本文想尽量简单些),并构造出单个 I 类型:

1
& : (Type, Type) -> Type  // 意会一下,我们就不引入 kind 的概念了

上文中 T 的类型可表示为 T : Fly & Swim & Run

& 像加法一样具有结合律,所以实现的时候不太需要关注它到底是左结合的还是右结合的,随意啦。

如果还是觉得不好理解的话,不妨回想一下函数类型 T -> R,我们可以说 -> 是函数类型的类型构造器

1
2
3
-> : (Type, Type) -> Type

// 把 Int -> Bool 理解为 ->(Int, Bool)的结果好了

I 类型的简要介绍到此为止,下面我们谈谈它与参数化多态特设多态函数重载非确定性(链接是非确定性图灵机的,凑合一下)的关系。

I 类型与函数重载

如果同一个作用域下的函数 f 定义了好几次且构成重载,那么 f 具有什么类型呢?我想聪明的读者应该已经想到了,很明显,f 可以具有 I 类型。

1
2
f : Int -> Int
f : Double -> Double

我们不妨把 f 的类型写成 Int -> Int & Double -> Double。为了少写几个括号,我们假设 -> 的结合性比 & 更强。

这样的 f,既可以处理整数,也可以处理浮点数,因此 f(1) (假设 1 不符合浮点数语法)与 f(1.0) 均为合法的调用——前者选用 Int -> Int 的逻辑处理,后者选用 Double -> Double 的逻辑处理 。

如果再给 f 新增一个能处理布尔类型的定义

1
f : Bool -> Bool

那么函数调用 f(true) 也将是合法的,此时 f 的类型将变成 Int -> Int & Double -> Double & Bool -> Bool

那么 I 类型可以替代重载吗?我认为取决于需求。

I 类型的类型检查与非确定行为

根据《Programming with Intersection Types and Bounded Polymorphism》,I 类型的类型检查会“穷尽每一种可能”。在做函数调用 f(t)时,如果 ft 都是 I 类型,那么每一组可以“匹配”的类型都会产生一个结果类型;如果“匹配”的类型超过一个,那么函数调用的结果类型仍然是一个 I 类型,例如:

1
2
3
4
f : Bool -> Bool & Bool -> Int
t : Bool

f(t) : Bool & Int

因为 fBool -> Bool 部分和 Bool -> Int 部分都可调用,所以它们会分别接受参数 t 并且生成结果。生成的结果亦使用 & 相连组成一个 I 类型。

这里便可以看出传统的 I 类型检查中的函数调用与常见的函数重载的不同了:函数重载会根据参数类型选取一个特定的、在某种条件下“最优”的 f 类型,如果无法选取则报错——例如此例中,没有其他更多信息时 f(t) 这个调用是要报类型错误的,而 I 类型会枚举并尝试每一种可能。

下面再看另一个例子,加深对 I 类型的函数调用的理解:

1
2
3
4
f : Bool -> Bool & Int -> Int & Double -> Double
t : Bool & Int

f(t) : Bool & Int

这里函数本身和入参都是 I 类型。入参 t 既有 Bool 的特质也有 Int 的特质:

  • t 呈现 Bool 的特质时,f : Bool -> Bool 这部分特质是可应用、“匹配”的,函数调用的结果为 Bool 类型;
  • t 作为 Int 时,f : Int -> Int 这部分特质时可应用的,函数调用的结果为 Int 类型。

因此 f(t) 的结果仍然为 I 类型的 Bool & Int。此即为 I 类型的类型检查中最“有趣”的部分。

由此我们还能得到另一个结论,I 类型与函数重载都是特设多态,而不是参数化多态,因为其对不同入参类型的处理逻辑不同。

如何构造 I 类型的数据

如果 I 类型是由函数类型组成的,似乎我们还可以通过多次定义同名函数来实现;但上文中我们使用了 t : Bool & Int 这种神奇的数据,那么这种数据是如何构造出的呢?

答案其实很简单,也很复杂。简单性在于只需要引入一种新的数据构造语法:正如(,) 语法可构造出 tuple 类型,我们可以新增例如 (,,)这样的语法来构造出 I 类型的数据。

1
2
3
4
5
6
7
true : Bool

1 : Int

(true, 1) : Bool * Int // tuple type

(true ,, 1) : Bool & Int // intersection type

而复杂性在于其背后的实现,(我猜)没有 IR 支持 I 类型,所以翻译到 IR 前,表层语言的 I 类型需要通过“解糖”或者其他(elaboration)手段消除,而这份工作显然没有那么轻松。

I 类型与 Bounded Quantification

简单的 I 类型与简单的 bounded quantification 是可以互换的。看下面的函数定义

1
2
3
4
5
6
7
class C {}

Bool f<T extends C>(T) { return true }
// f : <T <: C>. T -> Bool

Bool f<T>(T & C) { return true }
// f : <T>. (T & C) -> Bool

直观来看,其实这两个函数定义说了同一件事:别管实际的入参是什么类型,它都要具备 C 类型的所有特质——即为 C 类型的子类型——其他特质我不管。

由于本文只是入坑指南,更详尽的例子和解释请参考文中提到的论文。

其他话题

  • I 类型与 tuple 类型很像,但显然不等价,它们的关系是?
  • I 类型该如何设计,是否要具有幂等性?
  • I 类型该如何设计,是否要求组成类型没有交集?(是否要设计成 disjoint intersection types)
  • 如果类型系统等价于逻辑系统,那么 I 类型是否等价于逻辑中的“与”?还是说 tuple 类型才是逻辑中那个深入人心的“与”?
  • ……

问题总比方法多,欢迎各位观众老爷前往挑战 I 类型。


微信编程语言 Lab 公众号也有转载。

https://mp.weixin.qq.com/s/A_hiVgZCOpPka700eLLiRg

2021 年 7 月 24 日

大暑前后,台风洪水比较多。前几天是郑州和周边城市被干,今天是杭州周边城市被干。本着不给防风防洪防汛添乱的原则,周末就宅在家里哪也没去。

其实本文也没什么实质性内容,就是随便查查,查完随便喷喷,喷完随便写写,写完随便删删。激发我查阅兴趣的主要有三点:一是在家闲的,难得的时间;二是在杭州滨江区生活了一年多。因为一到雨天就看见柏油马路就到处是水坑,又见过三次排水口被堵(其中一次水已没过人行道,在创伟科技园旁边),一直觉得滨江区排水不畅;总觉得郑州那个雨量换到滨江的话,滨江应该已经成亚特兰蒂斯了。三是对郑州这百年一遇乃至“千年遇一”的自然灾害比较好奇。

目录

  • 郑州、河南历史上的雨灾
  • 东京的排水能力
  • 杭州对烟花的应对方式
  • 宁波余姚水灾与“浙江滚出中国”
  • 我对杭州的感观:杭州的基建与发展

郑州被干

郑州的降雨量确实大,7 月 20 日 16 时至 17 时,峰值雨量为 201.9mm,而 24 小时平均雨量达 253mm。可能很多人(尤其是文科生(没有贬低的意思))对降水量没有什么概念,不过可以回想起 400mm 等降水线的概念,这个概念告诉我们很多地方一年只下 400mm的雨——即使一年只有少到 50 个雨天,那平均每个雨天只有至多 8mm 的降雨,253mm 就是30多倍。或者这么看,郑州以往的平均年降雨量为 640.8mm,而近三天的降雨量为617.1mm,三天顶一年。

河南不是第一次被干,这次的雨也不是最大的

我很好奇这么大的雨是不是史无前例,就顺着微博上的 758 关键字查了查。原来 758 是指 1975 年 8 月的一场洪水。1975 年 8 月,河南驻马店不幸承受了史称 758 特大洪水的灾难。当年的 8 月 5 日至 6 日,板桥雨量站测得日降雨量为 448.1mm(不过最大每小时峰值雨量小一些,只有 142.8mm),位于灾难中心的泌阳林庄8月7日一天的降雨量达到1005.4mm,最大 6 小时降雨量更达到 830.1mm。有兴趣的可以自行搜索。

这种雨沿海大城市也顶不住

这样的大雨,我直观感觉有天然泄洪优势的沿海城市也是顶不住的。比如我们可以看看东京的泄洪能力——只因我在东京待过 5 年,期间几乎没见过积水,所以感觉东京的排水是相当好,就拿出来作个对比。

东京有个叫做首都圈外郭放水路的工程(可以网上搜搜图,围观一下,毕竟也是热门旅游景点),修了 14 年,大概 130 多亿人民币。这个工程的排水能力是每小时可承受最多 50 毫米的降水,并且在人口和建筑稠密的三个城区可承受 65-75mm 的降水。所以光看排水能力,一样顶不住 200mm 的峰值降雨。即使算上 67 万立方米的总贮水量,我算下来也是不够的,而且差距非常之大。不过如果峰值小一些,全天的降水倒还是真的可以顶住……

烟花来了,杭州怎么顶

烟花带来的降水与前面提到的史诗级灾难比起来并不算大,但听说萧山区已经有些地方被水淹没、不知所措了。

我在网上并没有查阅到关于萧山的新闻,倒是搜到了一票为杭州市防风防汛歌功颂德的新闻,比如

截至7月23日15时,各区、县(市)、管委会绿化管理部门、养护企业已清理断枝植物723株,26.51吨;已支撑树木数量46453株,其中已支撑行道树21545株,扶正倒伏树木23株。

全市共发送雨情预警通告单18份,发送各类预警短信3762条;出动水利技术力量68组634人次,对805处水利工程进行防台检查;全市大中型水库已全部降至汛限水位以下,并通过发电预腾库容;钱塘江沿线闸门开闸预降,萧绍平原和上塘河开始预排,累计预排水量1168万立方米,上塘河水位已由3.30米已降至2.89米;钱塘江沿线闸泵共发布调度指令8条,执行调度预排预泄排涝43台时,预排水量1132万立方米。

部分“老牌”积水点,也是各地各部门提前布防的重点。记者从杭州市城管局了解到,目前,该局已先后组织开展5轮汛前隐患大排查大整治,主要围绕排水设施、城市道路、户外广告、下穿桥涵、河道围堰等重点设施、部位,以及钱江新城、天目山路沿线等重点区域。累计清疏管网长度达7436公里,排查发现的风险隐患均已完成工程整改或落实应急处置“一点一方案”。

感觉杭州可以啊。于是又反手搜了搜郑州的,似乎没啥相关新闻,只搜到了说让停课停工却不听话的新闻。不知是杭州风险意识和宣传双到位,还是郑州确实菜,又或者是单纯地被后续新闻淹没了。不过有下面的讨论,评论区挺尖锐的。

这次郑州的大雨应急工作,对照本人既往经历,感觉存在不少问题,但这个问题不是懒政、不作为或者乱作为的问题,是应急经验欠缺的问题……

我随后望了望窗外,西兴这小破地方百来米的马路上有30来块井盖(虽然大部分应该是燃气光纤电缆相关的),顿时感觉滨江区可能也没那么糟糕。

浙江滚出中国

查着台风与洪水的话题,最后还是来到了 2013 年宁波余姚的水灾事件。这事情 ZF 处理得不是很好,像黑历史一样,但我觉得应该也是真的。

2013年宁波水灾是2013年10月发生在浙江宁波的一起由台风引发暴雨造成的严重水灾。水灾中,甬江流域遭遇有水文记录以来最大规模的降雨,加之天文大潮的影响,宁波多地发生严重内涝,交通、电力长时间大面积中断,其中尤以余姚市发生的灾害最为严重。据统计,宁波全市遭受经济损失超过333亿元,受灾人口达到248万人

当时余姚过程降水量达到 496.4mm,其中张公岭站达到 809mm,也是巨大,本应得到救助与同情。但因入驻的央视记者粉饰太平,在重灾区的路上睁眼说瞎话说没洪水了,直接被愤怒的市民围堵了,也有说被掀翻的。我只能说活该吧,没缺胳膊少腿不是挺好的?下面是看到的一两段网友描述,我觉得应该是真的吧,真收了 5 美分的话也不至于在冷门帖子下面讨论:

我就是余姚的,当时灾情真的很严重,经济损失很大,很多天城区、城镇交通都是瘫痪的,电视台也只有浙江台和宁波台真实的播放了水灾情况,央视新闻也是过了一段时间才轻描淡写的播了一下而已,热搜挂着余姚滚出中国,浙江滚出中国,网友还说浙江人有钱,可以自救,这些都是事实。从那个时候开始,我宁可把钱丢水里,也不往外捐了…

那时候我家还在余姚老城区,整整一个星期,断电断水,楼下积水淹到腰,在水里泡了好几个钟头走路去把家里的老人接过来,一家人靠一个收音机获取外界信息,慈溪人开着大卡车过来给我们送蜡烛食物和充电宝

哈哈哈,我还有照片…什么毛宏芳滚回奉化种田…市政府门口的为人民服务牌子都被人拆了。发洪水当天晚上我收留了一帮外地人,身边将近 40 万现金,提心吊胆一晚上,生怕他妈的被人抢了,当时已经做好准备了,真的要抢就让他们抢,钱是国家的,命是自己的。我还免费供应了矿泉水,面包,红牛。也算是出了把力。军队的话,我说说我看到的吧,南京军区的部队开进来了,当时我对面是梨洲街道派出所,那里有个救灾物资发放点,当时就发了一点点物资,(几箱矿泉水,还没我发的多)拍了个照部队就转移了,亲眼所见,所言非虚。

再然后呀,热搜就有了“浙江滚出中国”这一条,还占了一天的头条位置。

那次的事件好像处理得非常不好,似乎余姚没太收到外界捐赠,之后官方也不太组织捐款。

捐款捐出一堆白眼狼呗,还好从那之后就再无官方捐款

这两年知道2013年的事情才想起来似乎有好多年学校没有组织捐款了….

余姚水灾之后,浙江给全国的捐款从此少了很多。那些老乡省份人士目的达到了

这倒是真的,那两年之后就再没捐过款了,之前不捐还要被老师拉办公室谈话

我只想说,世界真大……真的清一色全是情绪极强的话,感觉那个市的市民受到了成吨的伤害

从那以后心彻底寒了,甚至看见一些外省贫困地区的儿童午餐留守儿童啊那些捐款的活动,我觉得他们可怜可是我一点都不同情他们,也不会再捐款。还有我出去买东西和淘宝购物也尽量挑发货地浙江的。我曾经有过爱心,会帮助别人,但是余姚事情让我认清楚了不是每个你帮助过的人都会在你困难的时候伸出援手,他可能会对你说:“活该”。

真的我记得我小学的时候我们学校常常组织捐钱给贫困山区 包括其他地方发生了天灾 我们也捐 直到那一年隔壁的余姚台风很大 发生了水灾 印象中记得老师眼眶微红说:竟然没一个地方捐款…

余姚那事真的是心寒了,以前别的省有事,每次都捐款,这次自己省有事,其他省让我们滚出中国!受灾那么严重,除了省内新闻,央视都轻描淡写而过,心寒

看看户口,现在我也是浙江集体户,属于人下人了。不小心搬过去的。

最后说点别的,关于浙江与杭州

浙江省确实挺逗的,经济不错,但(建国后)高校就有点难堪。说好听点,全省最差的 211 是浙江大学,全省最差的 985 也是浙江大学。浙江省高校就这,但院士还挺多,全国院士最多的省份是江苏,有两院院士 477人,第二就是浙江,有两院院士 407 人,第三名山东已经不到 200 人了。(不过这也就随口说说,毕竟院士里也有一部分专业水平比较菜的。)

我对杭州的印象挺好的。

从政府方面来看,很多政务服务可以网上办理,去当面办理时态度也比较好。政府的标语是“最多跑一次”,而且办理速度还很快,我的租赁补贴申请后,两三天就通过且拿到当月的补贴了。滨江政府的楼和图书馆(内部)等也都挺好看的。

杭州市的地铁修得挺快的,赶上了亚运会的快车道,已通车的已接近 10 条线,共规划 16 条。杭州市很多地铁站都有自己独特的吊顶设计,我不知道是不是每个站都不一样,但我上下车和换乘的每个站好像都不一样(主要是 1 号线,4 号线,5 号线等),感觉挺好。另外有些地铁站无论是站内(闸机内)还是站外都有厕所,这一点好上加好。(南京相反,很多地铁站没厕所,而且没有修缮计划。我真的看不到“徽京”的前途。)

杭州市的主要交通枢纽杭州东站设计得也挺好的,与地铁接续较快,厕所多而干净。可能大家不知道杭州东站的客流量,它其实客流量巨大,峰值在全国第二、第三的水平。关于杭州东站功能性的设计以及如何能让各路神仙列车入站,可以看这一篇知乎文章。(我研究杭州东站,一开始只是好奇“南京南的厕所这么脏(脏到有点无法忍受),杭州东的厕所这么干净,是不是单纯因为客流量不同呀。”结果却令人失望:如果相关,那也是负相关。)另外还得知了去上海的超导磁悬浮去年又提上了日程,到时候去上海城际只需 25 分钟。

杭州地铁、高铁、机场、景区等的告示牌与导引信息较为充足——与上海比起来,(当年)上海的虹桥火车站和虹桥机场差点把我气疯。举例来说,地铁站里能看到站外公交信息。而虹桥给我印象很深的一件事是,闸机都是三杆子滚动的,大行李箱过不去;以及我过了机场安检在电子显示器上看到的还是高铁发车车次信息,我愣是找不到在哪个柜台值机的信息。感觉那会儿上海俩机场加一个高铁站经常让我感到崩溃,我甚至到了见一个人就要吐槽一次的地步。(我很久没去过上海了,不知是否有好转。)

杭州主城区小,商圈比较密集,逛街较为省心。

杭州一些新修的冷门博物馆也很有意思,除了展览外,还有亲子互动区和体感游戏等。展览也不仅只有功能性,比如我认为其展台从设计上来说颇具美感,它的配色、打光、形式还是挺值得学习的。甚至有些展台还自带布景和音效的。

杭州是真的富,之前一次去安徽绩溪旅行,返程时因大雪和低温导致道路结冰,公交不通,只有当地“民营”的接驳车,而从绩溪开往临安的路,就如同从地狱通往天堂的路,也算是见识了……绩溪那边的路况堪称地狱级别,因为低温冰封,道路很窄;而山谷间还在开路和拓宽车道,所以能使用的车道就更窄了。而开路和拓宽车道的工程,导致路上坑坑洼洼、大小碎石堆积,行车颠簸不已。有时遇到施工工程车,又是黄土漫天。偶尔会通过沿道路两旁建设小屋的小镇,可以看到开着的小商铺,人们在太阳下下棋、打牌、闲聊等,也有的会去凝视经过的汽车。不知为何,那里有点(游戏里的)中东战地的感觉……然后开着开着,猛然上了柏油马路,马路上的白线黄线像新刷上去的一般,格外清晰;两旁的楼也变得错落有致,房顶颜色不一……感叹:贫富差距真的大。再看看 2018 年中国财政税收上缴数据,只有 8 个省是缴了钱的,其他省都在领钱。

总体来说,我挺看好这个城市的,它的基建和一些现在不很引人注意的地方,十年、二十年后将会发挥价值。除了夏天常年 45-50 度的体感热到人要暴毙。

包装严实

2021 年 5 月 20 日

印象中不少客户对网购的物流服务的好评会用上“包装严实”这个词。但我们真的需要“包装严实”吗?我们需要的只是物品完好无损吧。严实的包装拆起来可能贼费劲儿,我真巴不得不包装——若是仍能完好无损地送到。

后记:认真想了想,某些需要修改收件人姓名的特殊物品好像确实需要“包装严实”……

被包养与去工厂

2021 年 5 月 11 日

洗澡的时候隐约觉得找人包养与去工厂打工本质上好像也没什么不同,毕竟说白了都是为别人提供价值。只不过找人包养是为个别人提供某个价值,市场较小,不太稳定。而去工厂打工是为很多人提供某个价值,市场较大,因此也比较稳定。

说到实现自己的价值,也许找人包养比起修福报更容易实现自己的价值,还真说不准。

0%