11-Simple Extensions

基本类型 Base Types

A B C 表示基本类型 base types / atomic types 名称,$ A $ 表示基本类型组成的集合

当展示求值的结果时,将省略 λ 抽象体,直接简记为一个 <fun>,比如

λx : B . x
> <fun> : B → B

单位类型 Unit Types

Unit 类型的成员只有 unit

Derived forms 在下一节

Unit 在带副作用的语言中有很重要的作用;主要应用在带副作用的操作的语句(例如赋值语句)

导出形式:序列

对序列中的两个或者多个表达式求值 t1; t2,求值 t1 然后丢掉结果求值 t2

有两种方法去规范地定义序列

The high-level typing and evaluation rules for sequencing can be derived from the abbreviation of t1;t2 as (λx:Unit.t2) t1. This intuitive correspondence is captured more formally by arguing that typing and evaluation both “commute” with the expansion of the abbreviation.

也就是说序列的更高级的类型化和运算可以从后面这个 lambda 形式导出

定理

The advantage of introducing features like sequencing as derived forms rather than as full-fledged language constructs is that we can extend the surface syntax (i.e., the language that the programmer actually uses to write programs) without adding any complexity to the internal language about which theorems such as type safety must be proved.

我们可以扩展表面语法而不使语法的内核复杂化

通配符

Another derived form that will be useful in examples later on is the “wild-card” convention for variable binders. It often happens (for example, in terms created by desugaring sequencing) that we want to write a “dummy” lambda-abstraction in which the parameter variable is not actually used in the body of the abstraction. In such cases, it is annoying to have to explicitly choose a name for the bound variable; instead, we would like to replace it by a wildcard binder, written _. That is, we will write λ_:S.t to abbreviate λx:S.t, where x is some variable not occurring in t.

之前我们写出了一个虚拟的 λ,而囿变量 x 是一个实际上并不在抽象体中的变量,这个时候我们用通配符 _ 指代这种参数变量

归属

t as T 将一种类型 T 归属到给定的项 t

The typing rule T-Ascribe for this construct (cf. Figure 11-3) simply verifies that the ascribed type T is, indeed, the type of t. The evaluation rule E-Ascribe is equally straightforward: it just throws away the ascription, leaving t free to evaluate as usual.

归属的作用有:

  • documentation 使程序容易阅读

  • 让复杂类型便于编写(一种缩写机制),比如:

UU = Unit → Unit

UU 表示 Unit → Unit 的一个缩写

(λf : UU . f unit)(λx : unit . x)

  • 抽象机制 abstraction

let 绑定

OCaml 中已经见过,let 给表达式绑定一个名称;let x = t1 in t2 表示对 t1 求值,在计算 t2 时把 x 绑定为 t1 的结果

let 也可以被表示成一个导出形式:

But notice that the right-hand side of this abbreviation includes the type annotation T1, which does not appear on the left-hand side.

等式左边并不包含 T1 这个类型信息而右边包含

_We discover the needed type annotation simply by calculating the type of t1.

意味着我们要通过类型推断得到 t1 的类型

More formally, what this tells us is that the let constructor is a slightly different sort of derived form than the ones we have seen up till now: we should regard it not as a desugaring transformation on terms, but as a transformation on typing derivations (or, if you prefer, on terms decorated by the typechecker with the results of its analysis) that maps a derivation involving let.

形式上的解释是,let 的导出形式与目前所有的已知的导出形式不同,不是项上的转换,而是类型推导的一个转换:

序偶

注意隐含的求值顺序(从左到右)

元组

记录

与大部分高级语言带给我们的直觉相符:元组可以看作一种特别的记录,比如:元组 {Nat, Bool, Bool} 可以看作记录 {0: Nat, 1: Bool, 2: Bool} 的一种缩写

和 sum

这一部分不太符合直觉,所以讲下来由

在很多程序设计中,会需要统一的处理异类,比如:在二叉树中叶子节点没有左右孩子而内部结点则可能有一个或两个,支持我们这么做的数学基础是变式类型 variant types;在介绍变式类型之前先引入和类型 sum types

比如:

我们定义一个类型 Addr 统一地处理它们:

通过一个标记 inl inr 来表明当前的 Addr 具体上由哪种子类型带来:

if pa is a PhysicalAddr, then inl pa is an Addr.

但是并不把 inlinr 看作一种函数关系

我们可以这样抽取一个元素的值:

When the parameter a is a PhysicalAddr tagged with inl, the case expression will take the first branch, binding the variable x to the PhysicalAddr; the body of the first branch then extracts the firstlast field from x and returns it.

阶段性的形式化表述如下:

在上面的形式化表述中,类型唯一性 Uniqueness of Types 失效了

The difficulty arises from the tagging constructs inl and inr. The typing rule T-Inl, for example, says that, once we have shown that t1 is an
element of T1, we can derive that inl t1 is an element of T1+T2 for any type T2.

目前的选择是:给 T2 添加类型注释

不再使用 inl t 而是 inl t as TT 说明了 t 隶属的整个和类型

变式类型 variants

关于变式的一个用法是:可选值 optional value,比如:

首先定义一个变式:

The type OptionalNat is isomorphic to Nat extended with an additional distinguished value none.

再定义一个 Type 类型,表现为一个函数:

Table represents finite mappings from numbers to numbers: the domain of such a mapping is the set of inputs for which the result is <some=n> for some n.

那么对于一个项 emptyTable,定义为一个常量函数:

构造:

这个 Lambda 表达式的主要目的是在表格中更新或扩展特定键的值。如果键存在(n 等于 m),则返回一个包含新值的 OptionalNat;否则,返回表格 t 中键为 n 的位置的值。

if t is our table and we want to look up its entry for 5, we might write

x = case t(5) of
<none=u> ⇒ 999
| <some=v> ⇒ v;

providing 999 as the default value of x in case t is undefined on 5.

Also, the null value in languages like C, C++, and Java is actually an option in disguise.

枚举类型

枚举类型是一种退化了的变式类型,每个字段类型都是 Unit,比如:

单字段变式

可以用来给单个类型的数据打上 tag 以阻止一些无意义行为

递归

fix 并不能直接的引入简单类型 lambda 表达式,所以这里添加 typing rules 并用 letrec 来模仿无类型 λ 演算中 fix combinator 的行为。

大部分程序语言中用到 letrec,它也是一个导出形式:

列表

posted @ 2024-02-01 21:10  sysss  阅读(7)  评论(0编辑  收藏  举报