精化类型简介

作者简介

詹博华

麻省理工博士后,现任中科院软件所硕导,研究方向为形式化方法(交互式定理证明、嵌入式系统的建模和验证)。

本次技术分享来自 SIG-类型系统技术沙龙,本文内容由詹博华老师会后整理,视频也已经发布在 B 站,欢迎大家点开学习。
https://www.bilibili.com/video/BV1yS4y1X7pi


精化类型 (refinement types) 在普通类型的基础上添加了对变量取值范围的约束,从而可以用于保证程序不存在除零、数组越界等错误,甚至完全验证程序的功能正确性。在这篇文章中,我们将介绍精化类型的基本原理,并通过几个简单的例子展示精化类型的类型检查和类型推断方法。

本文的主要参考文献是 [1] Jhala and Vazou. Refinement Types: A Tutorial (arxiv:2010.07763, 发表于 Foundations and Trends in Programming Languages, 2021)。

该文从一个简单的程序语言开始,逐步添加新的特性,通过这种循序渐进的方式介绍精化类型的理论。本文的很多公式和例子均来自这篇文章。

普通类型系统及其局限性

类型系统是程序语言设计的一个重要组成部分。类型描述程序中每个变量的取值范围,每个函数的参数和返回值范围,等等。通过 类型检查(type checking),可以判断程序是否存在类型不匹配问题,从而在编译时提前发现运行时可能出现的错误。通过 类型推断(type inference),类型系统可以自动计算部分变量或函数的类型,减少用户需要做的类型标注。

类型系统可以捕捉很多常见的错误,例如在函数期待字符参数时输入一个整数参数。然而,其他一些常见的错误不能被普通的类型系统捕捉到,例如:

除零错误: 对于表达式 a / b a/b a/b,类型系统可以检查 a a a b b b 是相同的数值类型,但不能检查 b ≠ 0 b\neq 0 b=0

数组越界错误: 对于表达式 a [ i ] a[i] a[i],类型系统可以检查 a a a 是一个数组并且 i i i 是一个整数,但不能保证 0 ≤ i < a . length 0\le i < a.\textrm{length} 0i<a.length

程序正确性: 普通的类型系统无法表达程序返回正确的结果,或维护数据结构的不变式性质。例如,对于函数 sorted ( a ) \textrm{sorted}(a) sorted(a),类型系统可以检查 a a a 和返回值都是列表,但不能保证返回列表是 a a a 的排序。对于二叉搜索树,类型系统无法保证插入操作维护二叉搜索树中元素的顺序关系。

精化类型

精化类型的主要思想是允许在类型中额外标注由谓词表达的对变量的限制。精化类型的基本形式是:

B   { x : P } B\,\{x:P\} B{ x:P}

其中 B B B 是一个基本类型, x x x 是变量名, P P P 是一个关于 x x x 的谓词。

我们展示几个简单的精化类型的例子。在很多程序的分析中,我们需要判断一个整数变量的符号,或者它是否等于 0。以下类型表示大于等于 0 的整数:

type nat = int{v : 0 <= v}

不等于 0 的整数可以表示为:

type nonzero = int{v : 0 != v}

下面,我们看一个更有意思的例子,用于检查是否存在数组访问越界问题。首先,我们定义返回数组大小的函数 size的类型为:

val size: x : array(α) -> nat{v : v = length(x)}

其中,α是数值中元素的类型。以上类型表示:size接受元素类型 α的数组 x为参数,返回一个自然数 v,满足 v = length(x)

获得数组在索引 i的值的函数 get类型为:

val get: x : array(α) -> nat{v : v < length(x)} -> α

表示:get接受元素类型 α的数组 x,以及一个自然数索引 v满足 v <length(x),并返回一个类型为 α的元素。熟悉依赖类型论的读者可以看出,精化类型具备依赖类型的一些特性,例如以上类型允许变量 x在谓词中出现。精化类型可以看作依赖类型的一个子集,对于依赖和谓词的使用有一些约束以保证类型检查的可判定性。

在给定程序中每个变量和函数的类型后,程序的类型正确性可以归结为谓词之间的蕴含关系,使用 SMT 求解器判定。SMT 是 Satisfiability Modulo Theories(可满足性模理论)的缩写,可用于判断包含布尔运算符( ∧ , ∨ , → , ¬ \wedge, \vee, \rightarrow, \neg ,,,¬)、算数运算符、未解释函数等的表达式是否成立。例如,使用 SMT 求解器可以很容易证明

x ≥ 0 ∧ x < 5 → y > 1 → x + y > 1 x\ge 0 \wedge x<5 \rightarrow y> 1 \rightarrow x + y > 1 x0x<5y>1x+y>1

是成立的。SMT 求解已有非常成熟的工具,例如 Z3, CVC4 等。

相比于类型检查,精化类型的类型推断更加复杂。这个过程可以归结为带未知谓词公式的求解,需要计算未知谓词,一般借助 Horn 求解器。我们在后面会给一个类型推断的实例。

精化类型首先由 Freeman 和 Pfenning 提出 [2]。Rondon 等人提出了基于抽象解释的类型推断算法 [3]。Bengtson 等人和 Swamy 等人分别开发了 F7 和 F * 工具 [4] [5],为一个类似于 ML 的函数式语言建立了精化类型系统,并用于密码协议实现的验证。除了 ML 系列的语言,精化类型还用于命令式的 C 语言 [6],以及惰性求值的 Haskell 语言 [7]。Swamy 等人在精化类型的基础上提出了 Dijkstra Monad 的概念 [8]。近期的一些工作包括相关证明工具的设计与实现 [9]

类型检查规则

我们使用一个简单的函数式语言解释精化类型的类型检查规则。表达式的语法定义如下:

e : : = c   ∣   x   ∣   l e t   x = e   i n   e   ∣   λ x .   e   ∣   e   x   ∣   e : t e ::= c\ |\ x\ |\ \mathrm{let}\ x = e\ \mathrm{in}\ e\ |\ \lambda x.\,e\ |\ e\ x\ |\ e : t e::=c  x  let x=e in e  λx.e  e x  e:t

其中, c c c 代表常量, x x x 代表变量, l e t   x = e   i n   e \mathrm{let}\ x = e\ \mathrm{in}\ e let x=e in e 声明并使用一个局部变量, λ x .   e \lambda x.\,e λx.e e   x e\ x e x 分别是 lambda 函数和函数的应用。最后 e : t e:t e:t 表示类型标注。

精化类型的类型检查规则分为四部分,使用不同的符号表示,它们分别是:

  • 逻辑表达式的正确性: Γ ⊢ c \Gamma\vdash c Γc,表示在环境 Γ \Gamma Γ 下,逻辑公式 c c c 成立。
  • 子类型关系: Γ ⊢ t 1 ≺ : t 2 \Gamma\vdash t_1 \prec: t_2 Γt1:t2,表示在环境 Γ \Gamma Γ 下, t 1 t_1 t1 t 2 t_2 t2 的子类型。
  • 类型生成 (type synthesis): Γ ⊢ e ⇒ t \Gamma\vdash e\Rightarrow t Γet,表示在环境 Γ \Gamma Γ 下,表达式 e e e 生成类型 t t t
  • 类型检查 (type checking): Γ ⊢ e ⇐ t \Gamma\vdash e\Leftarrow t Γet,表示在环境 Γ \Gamma Γ 下,表达式 e e e 可以具有类型 t t t

下面我们展示每一类命题的推导规则。逻辑表达式的正确性的推导规则如下:

S m t V a l i d ( c ) ∅ ⊢ c EntEmp \frac {\mathrm{SmtValid}(c)}{\emptyset\vdash c} \quad \textrm{EntEmp} cSmtValid(c)EntEmp
Γ ⊢ ∀ x : b .   p ⇒ c Γ ; x : b { x : p } ⊢ c EntExt \frac {\Gamma\vdash\forall x:b.\ p \Rightarrow c} {\Gamma; x:b\{x:p\}\vdash c} \quad \textrm{EntExt} Γ;x:b{ x:p}cΓx:b. pcEntExt

规则 EntEmp 表示任何 SMT 求解器可以证明的逻辑表达式都是正确的。规则 EntExt 表示如果表达式 c c c x x x 满足 p p p 的假设下是正确的,并且类型环境包含 x x x 具有精化类型 p p p,则 c c c 在该环境下是正确的。

子类型关系的推导规则如下:

Γ ⊢ ∀ v 1 : b .   p 1 ⇒ p 2 [ v 2 : = v 1 ] Γ ⊢ b { v 1 : p 1 } ≺ : b { v 2 : p

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值