指称语义学讲义

前言

我们的目的在于介绍domain论和指称语义, 并展示其是如何为推理程序行为提供数学基础的.

推荐书目

深入阅读

第1章 引论

幻灯片1提示了给出编程语言的形式语义的几种方法. 操作性方法于Part IB课程Semantics of Programming Languages中介绍, 而公理性方法在Part II课程Hoare Logic中刻画. 本课程讲义给出了指称性方法的一些技巧的简要导引. 指称语义学的目的之一在于以尽可能抽象且实现无关的方式描述编程语言的构造: 通过这种方法, 我们有可能获得对于某些概念的洞察, 而这些概念构成了编程语言以及其间关系的基础, 甚至有时还能理解在语言设计中实现这些概念的新方式. 当然, 验证指称性描述可以被实现是重要的. 换言之, 即将指称语义和操作语义联系起来: 我们将在之后刻画如何施行此事.

形式语义的风格

操作的.程序片段的意义基于程序执行过程中其可以施行的计算步骤定义.

公理的.程序片段的意义间接地通过程序性质的某种逻辑的公理和规则定义.

指称的.关心给出编程语言的数学模型. 程序片段的意义抽象地定义为某种适当数学结构的元素.

幻灯片1
指称语义的特征性质

  • 每个程序片段P被赋予一个指称P, 这是一个数学对象, 其代表了P对于完整程序的意义的贡献.
  • 一个程序片段的意义只由其子片段决定, 或者说指称语义是可复合的.
幻灯片2

第1.1节 指称语义的基本例子

考虑基本的编程语言IMP, 其相当于带有控制结构的算术和布尔表达式, 而这里的控制结构是由赋值, 顺序, 条件刻画的, 见幻灯片3.

指称语义的基本例子 (I):

IMP的句法

算术表达式: AAexpn_|L|A+A|其中n是整数, 而L𝕃, 𝕃是给定的位置的集合.

布尔表达式: BBexptrue|false|A=A|¬B|

命令: CCommskip|LA|C;C|if B then C else C

幻灯片3
译者注记. n_是代表整数n的句法.

为了给出一个编程语言的指称语义, 我们需要赋予每种程序片段的句法范畴以一个解释的domain (domain of interpretation), 然后复合性地描述各种形成程序片段 (phrase-forming) 的构造所对应的语义函数. 对于IMP, 幻灯片4到10给出了其指称语义, 并且这个语义也很容易在SML中实现.

指称语义的基本例子 (II)

语义函数
A:Aexp(State)B:Bexp(State𝔹)C:Comm(StateState)其中={,1,0,1,}𝔹={true,false}State=(𝕃)
幻灯片4
译者注记. 的含义是部分函数 (partial function). 另外, truetrue是不同的, 前者是句法, 而后者是一个数学对象.
指称语义的基本例子 (III)

语义函数A
An_=λsState.nAL=λsState.s(L)AA1+A2=λsState.AA1(s)+AA2(s)
幻灯片5
指称语义的基本例子 (IV)

语义函数B
Btrue=λsState.trueBfalse=λsState.falseBA1=A2=λsState.eq(AA1(s),AA2(s))其中eq(a,a)={true, 如果a=afalse, 如果aaB¬B=λsState.¬(BB(s))
幻灯片6
指称语义的基本例子 (V)

语义函数C
skip=λsState.s

注记: 从现在开始, 语义函数的名字都将省略.

幻灯片7
可复合性一例

给定部分函数C,C:StateState以及函数B:State{true,false}, 我们可以定义if B then C else C=λsState.if(B(s),C(s),C(s))其中if(b,x,x)={x, 如果b=truex, 如果b=false

幻灯片8
指称语义的基本例子 (VI)

语义函数C
LA=λsState.λl𝕃.if(l=L,A(s),s(l))
幻灯片9
顺序复合的指称语义

两个命令的顺序复合C;C的指称为C;C=CC=λsState.C(C(s))这实际上就是命令的指称 (即部分函数C,C:StateState) 的复合而已.


与之相对的是, 顺序复合的操作语义为C,ssC,ssC;C,ss

幻灯片10

第1.2节 例子: 作为不动点的while循环

幻灯片2所提及的可复合性的要求是相当tough的. 我们用以赋予程序片段指称的数学对象必须足够丰富, 因为需要支持建模所讨论编程语言的一切形成程序片段的构造. 某些形成程序片段的构造是容易处理的, 而其他一些可能就不那么容易了. 例如, 牵涉状态改变命令的条件表达式 [译注: 更准确地说, 应该是条件命令] 可以基于应用相应的分支函数于立即子表达式的指称给出其指称语义: 见幻灯片8. 类似地, 命令的顺序复合的指称语义可由从状态到状态的部分函数的复合操作得到, 如幻灯片10.

现在我们来考虑基本编程语言IMP的指称语义, 其扩展了IMPwhile循环:CComm|while B do C然而, 这种循环构造并不容易以可复合的方式解释!

while循环的转换语义为while B do C,sif B then C;(while B do C) else skip,s这暗示了其作为从状态到状态的部分函数的指称应该满足while B do C=if B then C;(while B do C) else skip我们应该注意到这不能直接用来定义while B do C, 因为右边恰恰包含有一个我们想要定义其指称的子片段. 使用顺序复合和if的指称语义, 以及skip的指称为恒等函数λsState.s的事实, 上面这条等式是在说while B do C应该是幻灯片11中给出的不动点方程的一个解.

while B do C的不动点性质

while B do C=fB,C(while B do C)其中, 对于每个b:State{true,false}c:StateState, 我们定义fb,c:(StateState)(StateState)fb,c=λw(StateState).λsState.if(b(s),w(c(s)),s)
  • 为什么w=fB,C(w)有解?
  • 若此方程具有多解, 那么选取哪一个作为while B do C呢?
幻灯片11

在赋予带有递归特性的编程语言以指称语义时, 这样的不动点方程经常出现. 自Dana Scott于60年代晚期的先驱性研究始, 一种被称为domain论的数学理论建立起来以提供一种背景环境, 其中我们不仅总是可以找到因指称语义而生的不动点方程的解, 而且还能选出在某种适切意义下最小的解, 而这实际上保证了指称语义和操作语义之间的协调配合. 关键的想法在于考虑用作指称的数学对象之间的一种偏序, 此偏序表达了这样的事实, 一个对象由另一个对象近似, 或者说比另一个对象携带了更多的信息, 或者说比另一个对象更加良定. 然后, 不动点方程的最小解可以被构造为对于解的近似升链的极限. 在下一章里, 这些想法将会变得从数学角度来说更加精确和一般, 但是目前先让我们具体地阐明该如何运用此想法解决幻灯片11中的特定问题.

为了确定起见, 让我们考虑以下特定的while循环while X>0 do (YXY;XX1)其中XY是两个不同的整数存储位置 (变量), 而位置的集合𝕃={X,Y}.

译者注记. 在某种意义上说, 将𝕃的元素既用作句法也用作讨论语义时所牵涉的概念对象是一种(司空见惯的)滥用. 但是, 只要满足目的就好.

在这种情形之下, 我们可以就取状态为赋值[Xx,Yy], 其中x,y, 这记录了位置XY的当前内容. 因此, State=(𝕃).

译者注记. 实际上, 幻灯片4中就已经定义State(𝕃)了.

我们正在试着将这个while循环的指称定义为一个部分函数w:StateState其应该是幻灯片11上的不动点方程w=fX>0,YXY;XX1(w)的一个解.

对于特定的布尔表达式B=(X>0)和命令C=(YXY;XX1), 函数fB,C恰好与幻灯片12上定义的函数f相同.

while X>0 do (YXY;XX1)

State=def(𝕃)D=def(StateState)对于while X>0 do (YXY;XX1)D, 我们寻求w=f(w)的一个最小的解, 其中f:DD被定义为f(w)([Xx,Yy])={[Xx,Yy], 如果x0w([Xx1,Yxy]), 如果x>0
幻灯片12
D上的偏序

  • D上的偏序:
    ww当且仅当对于每个sState, 如果ws上有定义, 那么w也在s上有定义, 并且w(s)=w(s). 另外一种描述是, w的图包含于w的图.
  • 最小元D w.r.t. :
    即全然未定义的部分函数, 或者说图为空的部分函数, 其满足对于每个wD, w.
幻灯片13

考虑幻灯片13上给出的D=(StateState)的元素之间的偏序. 注意到实际上就是前文所提及的"信息序"的具体化身: 如果ww, 那么ww有定义的地方都保持和w的一致, 但是它可能在其他一些参数上也有定义. 我们还应该注意到的是, D包含一个相对于此偏序的最小元: 对于全然未定义的部分函数, 我们将其记作, 它满足对于任意的wD都有w.

开始, 我们反复应用函数f以构造一个部分函数的序列w0,w1,w2,:w0=def;wn+1=deff(wn).使用幻灯片12上的f的定义, 我们发现w1[Xx,Yy]=f()[Xx,Yy]={[Xx,Yy], 如果x0undefined, 如果x1w2[Xx,Yy]=f(w1)[Xx,Yy]={[Xx,Yy], 如果x0[X0,Yy], 如果x=1undefined, 如果x2w3[Xx,Yy]=f(w2)[Xx,Yy]={[Xx,Yy], 如果x0[X0,Yy], 如果x=1[X0,Y2y], 如果x=2undefined, 如果x3w4[Xx,Yy]=f(w3)[Xx,Yy]={[Xx,Yy], 如果x0[X0,Yy], 如果x=1[X0,Y2y], 如果x=2[X0,Y6y], 如果x=3undefined, 如果x4并且, 在n1的一般情况下, 我们有wn[Xx,Yy]={[Xx,Yy], 如果x0[X0,Y(!x)y], 如果0<x<nundefined, 如果xn其中!xx的阶乘.

因此, 我们得到了一个部分函数的递增序列w0w1w2wn所有这些部分函数之并是元素wD, 其为w[Xx,Yy]={[Xx,Yy], 如果x0[X0,Y(!x)y], 如果x>0注意到wf的一个不动点, 因为对于每个[Xx,Yy], 我们有f(w)[Xx,Yy]={[Xx,Yy], 如果x0w[Xx1,Yxy], 如果x>0(根据f的定义)={[Xx,Yy], 如果x0[X0,Y1y], 如果x=1[X0,Y!(x1)xy], 如果x>1(根据w的定义)=w[Xx,Yy]实际上, 我们可以表明wf最小不动点, 意即对于任意的wD, 有w=f(w)ww.我们取这个最小不动点w作为while X>0 do (YXY;XX1)的指称, 其构造方式是下一章要证明的Tarski不动点定理的一个实例. 我们也应该注意到, w的确就是命令while X>0 do (YXY;XX1)的结构操作语义所给出的从状态到状态的函数, 见Part IB课程Semantics of Programming Languages.

第1.3节 练习

练习1. 在SML中实现IMP的指称语义.
练习2. 考虑幻灯片11上定义的函数fb,c:(StateState)(StateState)
  1. 根据n上的归纳证明fb,cn()=λsState.{ck(s), 如果存在0k<n满足对于每个0i<kb(ci(s))=trueb(ck(s))=falseundefined, 如果对于每个0i<nb(ci(s))=true
  2. wb,c:StateState是由wb,c=defλsState.{ck(s), 如果存在k0满足对于每个0i<kb(ci(s))=trueb(ck(s))=falseundefined, 如果对于每个i0b(ci(s))=true定义的部分函数, 证明wb,c满足不动点方程wb,c=fb,c(wb,c).
  3. 对于b=true=λsState.truec=skip=λsState.s, 描述函数fb,c. 什么样的从状态到状态的部分函数是fb,c的不动点呢? 相对于的最小不动点是什么呢? 这个最小不动点和while true do skip的操作语义所确定的从状态到状态的部分函数是一致的吗?
练习3. 说明幻灯片13上的关系的确是一个偏序, 而且是最小元.
练习4. 证明w的确是f的最小不动点. 更一般地, 根据幻灯片13和练习2的定义, 证明对于任意的w(StateState), 有w=fb,c(w)wb,cw.

第2章 最小不动点

本章介绍了被称为domain论的数学理论, 其为构造各种编程语言特性的指称语义中所用到的最小不动点提供了一个一般性的框架. 该理论是由Dana Scott提出的.

第2.1节 偏序集和单调函数

论点

  • 所有计算的domain都是带有最小元的偏序集.
  • 所有可计算函数都是单调的.
幻灯片14

第2.1.1小节 偏序集

domain论使用满足特定完备性质的偏序集. 我们在幻灯片15中回顾了偏序的定义. D被称为偏序集(D,)基础集(underlying set). 大部分时候, 我们只以基础集的名字引用偏序集, 而以相同的符号代表不同偏序集的偏序.

偏序集

集合D上的二元关系是一个偏序, 当且仅当它是
  • 自反的: dD.dd;
  • 传递的: d,d,dD.ddddd;
  • 反对称的: d,dD.dddd=d.
序对(D,)被称为一个偏序集.
幻灯片15
译者注记. ddddd&dd的缩写.
偏序集公理: 规则形式

xx
xyyzxz
xyyxx=y
幻灯片16
部分函数的domain, XY

  • 基础集: 由所有定义域dom(f)X且取值于Y的部分函数f构成.
  • 偏序: fg当且仅当dom(f)dom(g)xdom(f).f(x)=g(x), 或者说graph(f)graph(g).
幻灯片17
译者注记. 实在是一点可有可无且无聊的注记. 若AXBY, 那么应该将f:AB也视为XY的元素吗 (假设排除A=XB=Y的平凡情形)? 这是微妙的, 往往取决于具体的上下文.
例子1. 从集合X到集合Y的所有部分函数构成的集合(XY)可以看成是一个偏序集, 如幻灯片17那样. 前一章里, 我们取这个domain在X=Y=State (某个状态集合) 情形下的实例作为命令的指称集.

第2.1.2小节 单调函数

幻灯片18中给出了偏序集之间的单调映射的概念.

单调性

两个偏序集之间的函数f:DE单调的, 如果d,dD.ddf(d)f(d).
xyf(x)f(y)(f单调)
幻灯片18
例子2. 给定偏序集DE, 显然常函数λdD.e:DE是单调的.
例子3.D是部分函数的domain (StateState) (见幻灯片17) 时, 幻灯片11上定义的与while循环的指称语义有关的函数fb,c:DD是一个单调函数. 我们将其验证留作练习.

第2.2节 最小元和前不动点 (pre-fixed point)

定义1.D是一个偏序集, SD的一个子集, dS被称为S最小元, 如果其满足xS.dx.

注意到因为是反对称的, 所以S至多拥有一个最小元. 我们也应该注意到, 有的偏序集是没有最小元的. 例如, 带有通常偏序的.

函数f:DD的一个不动点, 根据定义, 是满足f(d)=d的一个元素dD. 如果D是一个偏序集, 我们可以考虑一个更弱的概念, 即前不动点, 见幻灯片19.

前不动点

D是一个偏序集而f:DD是一个函数.
一个元素dDf的一个前不动点, 如果其满足f(d)d.
f最小前不动点, 如果存在的话, 记作fix(f).因此, 最小前不动点由以下两条性质(唯一地)刻画:
  • (lpf1): f(fix(f))fix(f);
  • (lpf2): dD.f(d)dfix(f)d.
幻灯片19
证明原理

  1. f(fix(f))fix(f)
  2. D是一个偏序集, f:DD是一个带有最小前不动点fix(f)D的函数.
    对于任意的xD, 为了证明fix(f)x, 只需要证明f(x)x.f(x)xfix(f)x
幻灯片20
命题2.D是一个偏序集而f:DD是一个带有最小前不动点fix(f)的函数. 只要f是单调的, 那么fix(f)实际上就是f的一个不动点, 因此也是f的最小不动点.
证明. 因为fix(f)f的前不动点, 所以f(fix(f))fix(f). 如果f是单调的, 那么f(f(fix(f)))f(fix(f)).换言之, f(fix(f))也是f的一个前不动点. 但是, 鉴于fix(f)是最小的前不动点, 我们可以推出fix(f)f(fix(f)).根据偏序的反对称性, 我们可以断言fix(f)=f(fix(f))fix(f)f的一个不动点. 而且, 考虑到偏序的自反性, 不动点也是前不动点. 对于任意的dD满足d=f(d), 我们有fix(f)d. 换言之, fix(f)f的最小不动点.

第2.3节 完全偏序 (cpo) 和连续函数

论点*

  • 所有计算的domain都是带有最小元的完全偏序.
  • 所有可计算函数都是连续的.
幻灯片21

第2.3.1小节 domain

定义1.
  1. 若存在, 我们将偏序集D的最小元记为D. 若D在上下文中是已知的, 写成就可以了. 因此, 由性质dD.d唯一确定. 偏序集的最小元有时也被称为其底(bottom)元素.
  2. 偏序集D中的一个可数的升是由D的元素构成的一个序列满足d0d1d2这样的链的一个上界是任意满足n.dnddD. 若链的最小上界(lub)存在, 我们将其记为n0dn.因此, 根据定义:
    • m.dmn0dn.
    • 对于任意的dD, 如果m.dmd, 那么n0dnd.
译者注记. 所谓的链, 指的是偏序集的全序子集. 不过, 本讲义实际上只考虑以(通常的)序列面目出现的可数的升链.
评注2. 以下是读者应该注意的点.
  1. 我们不需要考虑偏序集中不可数的链, 或者降链: 因此, "链"将总是指可数的升链.
  2. 就和偏序集的任意子集的最小元一样, 链的最小上界若存在则唯一. 当然, 链可以没有最小上界, 例如中的012, 不过它连上界也没有.
  3. 最小上界有时也被称为上确界. n0dn的一些其他常见替代记号为n=0dn{dn|n0}.
  4. 链的元素不必是互异的. 实际上, 我们称一个链d0d1d2终至恒常, 如果存在N使得nN.dn=dN. 注意到此时n0dn=dN.
  5. 如果我们丢弃链的开头任意有限数目的元素, 也并不会影响其上界集和最小上界:N.n0dn=n0dN+n.
cpo和domain

一个链完备偏序集(chain-complete poset), 或者说缩写为cpo, 是一个偏序集(D,)满足其中的每个链d0d1d2都具有最小上界n0dn:
  • (lub1): m0.dmn0dn;
  • (lub2): dD.(m0.dmd)n0dnd.
一个domain是一个带有最小元的cpo:dD.d.
幻灯片22
译者注记. 幻灯片22的两个冒号后面的内容, 只是为了解释什么是最小上界和最小元. 另外, 链完备偏序集也被称为完全偏序, complete partial order.
最小元和最小上界的定义: 规则形式

x
xin0xn(i0xn是一个链)
m0.xmxn0xnx(xn是一个链)
幻灯片23

本讲义里我们关心的是具有特定完备性质的偏序集, 见幻灯片22. 读者应该注意的是, 在有关的指称语义的文献中, 术语"domain"的含义是相当宽泛的: 存在各种各样的domain, 它们可能具有各种各样的序论性质, 而不仅仅是满足链完备性质和拥有最小元.

例子3. 从集合X到集合Y的所有部分函数的集合(XY)上可以赋予一个偏序成为domain, 见幻灯片24. 在第1.2节, 我们使用了X=Y=State的特殊情形作为命令的指称集. 我们应该注意到, 声称是链f0f1f2的最小上界的f的确是一个良定的部分函数, 因为在有定义的地方, 每个fn的值都是一致的. 至于验证f的确是偏序集(XY,)中的f0f1f2的最小上界, 我们将其留给读者作为练习.
部分函数的domain, XY

基础集: 由所有满足以下条件的部分函数f构成, 其定义域dom(f)X而取值于Y.
偏序: fg当且仅当dom(f)dom(g)xdom(f).f(x)=g(x), 或者说graph(f)graph(g).
链的最小上界: f0f1f2的最小上界是部分函数f, 其dom(f)=n0dom(fn)f(x)={fn(x), 如果存在某个n使得xdom(fn)undefined, 否则的话最小元素: 是全然未定义的部分函数.
幻灯片24
例子4. 对于任意的偏序集(D,)而言, 如果D是有限的, 那么该偏序集是一个cpo. 这是因为, 在这样的偏序集中, 任何链都将终至恒常, 因而拥有最小上界. 当然, 有限的偏序集也不一定拥有最小元, 即不是一个domain. 例如, 考虑以下Hasse图所描述的偏序集.一个偏序集的Hasse图是一个有向图, 其顶点是偏序集的基础集的元素, 而从顶点x到顶点y有一条边当且仅当xyz.(xz&zy)(z=xz=y).
"扁平自然数集":012nn+1"垂直自然数集"Ω:ωn+1n210
图1

图1展示两个非常简单但却无限的domain, 而以下是两个并非cpo的偏序集的例子.

例子5. 装备有通常偏序的自然数集={0,1,2,}不是一个cpo, 因为链012中没有上界.
例子6. 考虑上图的第二个例子的一种修改版本, 其中我们为添加了两个不同的上界ω1ω2. 换言之, 我们考虑的是D=def{ω1,ω2}, 而其上的偏序dddef{dd, 如果d,ddd=d, 如果d{ω1,ω2}然后, D中的链012拥有两个上界, 即ω1ω2, 但是没有最小的上界, 因为ω1ω2不可比较. 因此, (D,)不是一个cpo.
链的最小上界的一些性质

D是一个cpo.
  1. 对于任意的dD, n0d=d.
  2. 对于D中的每个链d0d1dn, 我们有n0dn=n0dN+n对于任意的N成立.
幻灯片25
链的最小上界的一些性质 (续)

  1. 对于D中的两条链d0d1dne0e1en, 如果对于每个ndnen, 那么n0dnn0en.
n0.xnynn0xnn0yn(xnyn俱是链)
幻灯片26
双链的对角化

引理.D是一个cpo, 设双下标索引的元素dm,nD (其中m,n0) 构成的族满足mm&nndm,ndm,n那么我们有n0d0,nn0d1,nn0d2,n以及m0dm,0m0dm,1m0dm,2而且m0(n0dm,n)=k0dk,k=n0(m0dm,n).
幻灯片27
证明. 我们利用了定义链的最小上界的性质, 即幻灯片22上的(lub1)和(lub2). 首先, 注意到如果mm, 那么dm,ndm,nn0dm,n对于每个n0成立. 因此, n0dm,nn0dm,n. 于是, 我们的确可以得到一条由最小上界构成的链n0d0,nn0d1,nn0d2,n并且我们可以构造其最小上界m0n0dm,n. 运用两次(lub1), 我们有dk,kn0dk,nm0n0dm,n对于每个k0成立, 那么根据(lub2)可以得到k0dk,km0n0dm,n反过来, 对于每个m,n0, 我们注意到dm,ndmax(m,n),max(m,n)k0dk,k因而再应用两次(lub2)就可以推出m0n0dm,nk0dk,k根据的反对称性, 我们就得出了想要的等式. 剩余的结果也可按照相同的论证手法得到, 只需要交换mn的角色.

第2.3.2小节 连续函数

连续性和严格性

  • 如果DE是cpo, 函数f连续的当且仅当
    1. f是单调的;
    2. f保持链的最小上界, 即对于D中的每条链d0d1, 我们有f(n0dn)=n0f(dn).
  • 如果DE都拥有最小元, 那么称函数f严格的, 如果f()=.
幻灯片28
评注7. 我们注意到如果f:DE是单调的, 并且d0d1d2D中的一个链, 那么应用f就可以得到E中的一个链f(d0)f(d1)f(d2). 而且, 如果d是第一条链的一个上界, 那么f(d)是第二条链的一个上界. 换言之, 如果f:DE是cpo之间的单调函数, 我们总有n0f(dn)f(n0dn)因此, 根据的固有性质, 给定cpo之间的单调函数f:DE, f是连续的等价于对于D中的每条链d0d1d2, Ef(n0dn)n0f(dn)成立.
例子8. 给定cpo DE, 对于每个eE而言, 常函数λdD.e:DE是连续的.
例子9.D是部分函数的domain (StateState)时 (见幻灯片24), 定义于幻灯片11的与while循环的指称语义有关的函数fb,c:DD是一个连续函数. 我们将其验证留作练习.
例子10.Ω是垂直自然数的domain, 那么由f(x)={0, 如果xω, 如果x=ω定义的函数f:ΩΩ既是单调的也是严格的, 但是并非连续, 因为f(n0n)=f(ω)=ω然而n0f(n)=n00=0

第2.4节 Tarski不动点定理

Tarski不动点定理

f:DD是domain D上的一个连续函数, 那么
  • f具有最小前不动点, 由fix(f)=n0fn()给出.
  • 于是, fix(f)也是f的不动点, 因而是f最小不动点.
幻灯片29

幻灯片29给出了关于domain上的连续函数的关键结果, 其允许我们赋予牵涉递归特性的程序以指称语义. 幻灯片上所用的记号fn()是递归定义的:f0()=def;fn+1()=deff(fn()).注意到既然dD.d, 我们有f0()=f1(); 而根据单调性, 又可以推出fn()fn+1()fn+1()=f(fn())f(fn+1())=fn+2().因此, 通过对于n进行归纳, 我们可以得到n.fn()fn+1().换言之, 元素fn()构成了D中的一条链. 所以说, 既然D是cpo, 那么幻灯片29上用到的n0fn()的确是有意义的.

证明. 首先我们注意到f(fix(f))=f(n0fn())=n0f(fn())根据f的连续性=n0fn+1()根据函数的幂次的定义=n0fn()根据第2.3节的评注2=fix(f)因此, fix(f)的确是f的一个不动点, 当然也就满足幻灯片19上的条件(lpf1). 为了验证(lpf2), 即前不动点的最小性, 我们设dD满足f(d)d, 那么既然D是最小的, 可以得到f0()=d并且fn()dfn+1()=f(fn())f(d)d根据归纳, 我们可以推出n.fn()d. 换言之, d是链的一个上界, 所以它大于等于最小上界, 即fix(f)=n0fn()d这就是我们想要的(lpf2)了.
例子1. 定义于幻灯片11上的函数fB,C是domain (StateState)上的一个连续函数, 因而我们可以应用Tarski不动点定理, 将while B do C定义为fix(fB,C). 实际上, 第1.2节中我们构造部分函数w的方法不过就是不动点定理的一个实例而已.
while B do C

while B do C=fix(fB,C)=n0fB,Cn()=λsState.{Ck(s), 如果存在k0满足对于每个0i<kB(Ci(s))=trueB(Ck(s))=falseundefined, 如果对于每个i0B(Ci(s))=true
幻灯片30

第2.5节 练习

练习1. 验证幻灯片24上的断言.
练习2. 证明幻灯片25和27中的声明.
练习3. 验证例子9中fb,c是连续函数的断言. 何时fb,c是严格的?
译者注记. 以上练习皆相当平凡.

第3章 domain上的构造

本节我们将给出诸多构造domain和连续函数的方式, 实际上专注于PCF编程语言的指称语义所需的构造, PCF是本讲义的后半部分的研究对象. 注意到为了描述一个cpo, 我们必须先定义一个装备有某二元关系的集合, 然后证明

  1. 这个关系是一个偏序;
  2. 对于这个偏序集中所有的链, 其最小上界存在.
另外, 为了使得cpo成为一个domain, 我们还需要说明
  1. 存在最小的元素.
注意到既然链的最小上界以及最小元若存在则唯一, 那么cpo和domain完全由其基础集和偏序决定. [译注: 意味不明.] 之后我们将给出各种各样构造cpo和domain的方法, 而将验证i, ii, iii成立的任务留作练习.

第3.1节 扁平domain

为了模拟PCF的基本类型 (ground type) natbool, 我们将使用幻灯片31给出的扁平domain的概念.

离散cpo和扁平domain

对于任意的集合X, 相等关系xxdefx=x使得(X,)成为一个cpo, 其被称为以X为基础集的离散cpo.
X=defX{}, 其中是某个不在X中的元素, 那么dddef(d=d)(d=)使得(X,)成为一个以为最小元的domain, 其被称为由X确定的扁平domain.
幻灯片31

自然数的扁平domain , 上一章的图1中我们就已描绘过其图像. 至于布尔值的扁平domain 𝔹, 其Hasse图为truefalse以下牵涉扁平domain的连续函数实例对于PCF的指称语义而言也是必要的, 我们将其验证留给读者作为练习.

命题1.f:XY是两个集合之间的部分函数, 那么f(d)=def{f(d), 如果dXf定义于d, 如果dXfd上没有定义, 如果d=定义了相应扁平domain之间的连续函数f:XY.

第3.2节 domain的积

cpo和domain的二元积

两个cpo (D1,1)(D2,2)的基础集为D1×D2={(d1,d2)|d1D1&d2D2}而其上的偏序定义如下(d1,d2)(d1,d2)defd11d1&d22d2链的最小上界可以按照分量进行计算:n0(d1,n,d2,n)=(i0d1,i,j0d2,j)(D1,1)(D2,2)都是domain, 那么(D1×D2,)也是一个domain, 并且D1×D2=(D1,D2)
幻灯片32
命题1. 投影和配对.D1D2是cpo, 那么投影π1:D1×D2D1,(d1,d2)d1π2:D1×D2D2,(d1,d2)d2是连续函数. 如果f1:DD1f2:DD2是连续函数, 其中D是一个cpo, 那么f1,f2:DD1×D2,d(f1(d),f2(d))是连续的.
证明. 这些函数的连续性可由幻灯片32上对于D1×D2中的链的最小上界的刻画直接推出.
命题2. 对于每个domain D, 函数if:𝔹×(D×D)D,(x,(d,d)){d, 如果x=trued, 如果x=falseD, 如果x=是连续的.

我们将会需要以下更一般的积构造.

定义3. 依赖积. 给定集合I, 设对于每个iI我们有一个cpo (Di,i), 那么这个cpo族之就和二元积的情况一样, (iIDi,)中的链的最小上界也可以逐分量计算: 如果p0p1p2是积cpo中的一个链, 那么其最小上界是将每个iI映射至Di中的链p0(i)p1(i)p2(i)的最小上界的函数, 即(n0pn)(i)=n0pn(i),iI.而且, 对于每个iI, 第i投影函数πi:jIDjDi,pp(i)是连续的. 如果每个Di都是domain, 那么它们的积也是domain, 并且其最小元是将每个iI映射至Di的最小元的函数.
两个参数的连续函数

命题.D,E,F是cpo, 那么函数f:D×EF是单调的当且仅当其对于每个参数分别都是单调的:d,dD,eE.ddf(d,e)f(d,e)dD,e,eE.eef(d,e)f(d,e)而且, 其是连续的当且仅当其对于每个参数分别都是连续的 [译注: 在单调的基础之上, 也就是对于每个参数分别都是保持链的最小上界的]:f(n0dn,e)=n0f(dn,e)f(d,n0en)=n0f(d,en)
幻灯片33
两个参数的连续函数: 推导规则

  • f单调的情况下, 我们有xxyyf(x,y)f(x,y)
  • f连续的情况下, 我们有f(m0xm,n0yn)=k0f(xk,yk)
幻灯片34
证明. "仅当"的方向是直接的, 其证明依赖于简单的观察, 即dd(d,e)(d,e)(n0dn,e)=n0(dn,e), 以及它们之于右参数的对偶版本. 对于"当"的方向, 首先设f对于每个参数分别都是单调的, 那么如果D×E中有(d,e)(d,e), 根据二元积的定义, 我们可以推出D中有ddE中有ee, 因此f(d,e)f(d,e)根据对于第一个参数的单调性f(d,e)根据对于第二个参数的单调性于是, f(d,e)f(d,e), 即f是单调函数.
现在设f对于每个参数分别都是连续的, 那么如果(d0,e0)(d1,e1)(d2,e2)是二元积中的一个链, 我们有f(n0(dn,en))=f(i0di,j0ej)见幻灯片32=i0f(di,j0ej)根据对于第一个参数的连续性=i0j0f(di,ej)根据对于第二个参数的连续性=n0f(dn,en)根据幻灯片27上的引理而这就说明了f的连续性.

第3.3节 函数domain

两个cpo/domain之间的所有连续函数的集合可以赋予一个偏序而成为一个cpo/domain, 见幻灯片35. 有时我们也用术语"指数cpo/domain (exponential cpo/domain)"而不是"函数cpo/domain".

函数cpo和domain

给定cpo (D,D)(E,E), 函数cpo (DE,)的基础集为 [译注: 以下符号有点过载](DE)=def{f:DE|f连续}而偏序为ffdefdD.f(d)Ef(d)推导规则:f(DE)gxDyf(x)Eg(y)
幻灯片35
函数cpo和domain (续)

链的最小上界可以逐参数计算:n0fn=λdD.n0fn(d)推导规则:(n0fn)(n0xn)=k0fk(xk)如果DE还是domain, 那么DE也成为一个domain, 并且最小元为DE:DE,dE.
幻灯片36
证明. 我们应该证明函数的链n0fn的最小上界是连续的. 这个证明使用了幻灯片27的互换律 (interchange law). 对于D中的一个链d0d1d2, 我们有(n0fn)(m0dm)=n0fn(m0dm)n0fn的定义=n0(m0fn(dm))每个fn的连续性=m0(n0fn(dm))互换律=m0((n0fn)(dm))n0fn的定义
译者注记. 这个证明有点没头没脑, 所以我感到有必要写下注记. 原文写的是这是对于幻灯片35的证明, 这实际上就足够令人费解的了. 毕竟幻灯片35是一个定义, 那么需要证明什么呢? 这个证明的目的实际上是为了补足定义里的一点gap, 以使得定义的确是well-defined的. (译者很有先见之明的给幻灯片36取了合适的标题, 而的确要证明的内容和幻灯片36有关.) 我们知道一个cpo需要能够对于(升)链作最小上界操作, 而幻灯片36只是指出可以这么计算该操作, 没有说明这个计算结果的确是最小上界操作. 这个证明比较令人迷惑的地方主要是在证明之前就使用了n0fn这种符号, 实际上在证明的过程之中你不应该把它视为最小上界. 另外, 这个证明只是论证了保持最小上界这一性质, 其他还需要论证的内容是单调性, 然后在连续的基础之上说明这个计算结果的确是链的上界且是上界之中最小的. 当然, 额外的内容并不困难, 只是因为先前证明总是过分细致而显得这里省略这么多内容让译者感到有点奇怪.
命题1. 求值和Curry化. 给定cpo DE, 函数ev:(DE)×DE,(f,d)f(d)是连续的. 给定任意的连续函数f:D×DE (其中D是一个cpo), 对于每个dD, 函数dDf(d,d)都是连续的, 因而确定了函数cpo DE中的一个元素. 我们将其记为cur(f)(d), 那么cur(f):D(DE),dλdD.f(d,d)是一个连续函数. [原注: Curry化这个名字是为了纪念逻辑学家H. B. Curry, 一位组合子逻辑和lambda演算先驱.]
证明. 对于ev的连续性, 注意到ev(n0(fn,dn))=ev(i0fi,j0dj)积的最小上界是逐分量计算的=(i0fi)(j0dj)根据ev的定义=i0fi(j0dj)函数cpo中的最小上界是逐参数计算的=i0j0fi(dj)根据每个fi的连续性=n0fn(dn)根据幻灯片27的引理=n0ev(fn,dn)根据ev的定义每个cur(f)(d)以及然后cur(f)的连续性可以由D1×D2中的链的最小上界可以逐分量计算这一事实立即推出.
复合的连续性

对于cpo D,E,F, 复合函数:((EF)×(DE))(DF)是连续的, 其定义为对于f(DE)g(EF),gf=λdD.g(f(d)).
幻灯片37
不动点算子的连续性

D是一个domain.
根据Tarski不动点定理, 我们知道每个连续函数f(DD)都拥有一个最小不动点fix(f)D.
命题. 函数fix:(DD)D是连续的.
幻灯片38
证明. 我们必须首先证明fix:(DD)D是一个单调函数. 设f1f2是函数domain中的两个元素. 我们需要证明的是fix(f1)fix(f2), 不过f1(fix(f2))f2(fix(f2))鉴于f1f2fix(f2)根据fix(f2)的(lpf1)于是, fix(f2)f1的一个前不动点, 因而根据fix(f1)的(lpf2)我们有fix(f1)fix(f2), 这也正是我们想要的. [译注: 作者这里将lpf均误作lfp, 而lfp在书中并没有出现过, 证明的剩余部分也都写错了. 另外, 读者应该回忆一下, 根据之前的命题, 此时最小前不动点和最小不动点均存在且相等.]
现在我们将注意力转向证明链的最小上界的保持, 设DD中有f0f1f2. 根据第2章第3节的评注7, 我们只需要证明fix(n0fn)n0fix(fn)而根据最小前不动点的(lpf2), 证明n0fix(fn)n0fn的一个前不动点就足够了. [译注: 即最小前不动点小于其他的前不动点.] 这是因为:(m0fm)(n0fix(fn))=m0fm(n0fix(fn))函数链的最小上界可以逐参数计算=m0n0fm(fix(fn))鉴于每个fm都是连续的=k0fk(fix(fk))根据幻灯片27的引理k0fix(fk)根据每个fk的(lpf1)[译注: 这里根据幻灯片27的引理需要用到之前证明的单调性, 另外最后一步这里的实际上更确切地说是=, 因为fix是不动点算子, 不过这个证明的所有地方作者都把最小不动点当作最小前不动点使用.]

第3.4节 练习

练习1. 验证本章未经证明的构造, 证明本章未经证明的命题.
练习2.XY是集合而XY是对应的扁平domain, 如幻灯片31. 证明一个函数f:XY是连续的当且仅当以下条件之一成立:
  1. f是严格的, 即f()=;
  2. f是常函数, 即xX.f(x)=f().
练习3.{}是一个单元素集合, 而{}是相对应的扁平domain. 令Ω是图1所描绘的垂直自然数的domain. 证明函数domain (Ω{})Ω之间存在一个双射.
练习4. 证明幻灯片37的内容.

第4章 Scott归纳

第4.1节 链封闭子集和可容许子集

在第2章的时候我们看到一个domain D上的一个连续函数f:DD的最小不动点可以表达为自D的最小元素起反复应用f所得到的链的最小上界: fix(f)=n0fn(). 这种构造允许我们使用特定方式证明fix(f)的性质, 只要这个性质满足幻灯片39中的条件, 证明方式为使用数学归纳法表明对于每个n而言fn()具有该性质. 或许将这种对于数学归纳法的使用方式打包以隐藏fix(f)作为某个链的不动点的显式构造也是方便的, 见幻灯片40. 为了澄清幻灯片40的陈述, 注意到f0()=S, 此为基本步骤; 而fn()S可以推出fn+1()=f(fn())S, 此为归纳步骤; 因此, 根据n上的归纳, 我们有n0.fn()S. 最后, 根据S的链封闭性, fix(f)=n0fn()S, 这正是我们所要的.

链封闭子集和可容许子集

D是一个cpo. 一个子集SD被称为是链封闭的当且仅当对于D中所有的链d0d1d2, 有(n0.dnS)(n0dn)S如果D是一个domain, SD被称为是可容许的当且仅当其是D的一个链封闭子集且S.
元素dD的一个性质Φ(d)被称为是链封闭的当且仅当{dD|Φ(d)}D的一个链封闭子集, 类似地还可以定义可容许性质.
幻灯片39
译者注记. 所谓(D上的)性质指的是一个从D到真假的函数, 这是一种外延性的观念. 另外, 正如幻灯片39, D上的一个性质Φ也可以由子集{dD|Φ(d)}表示, 这和函数表示是完全等价的.
注记. 术语inclusive或者inductive经常用作链封闭的同义词.
例子1. 考虑图1所描绘的垂直自然数的domain Ω, 那么
Scott的不动点归纳原理

f:DD是domain D上的一个连续函数.
对于任意的可容许子集SD, 为了证明f的最小不动点在S之中, 即fix(f)S实际上证明dD.dSf(d)S就足够了.
幻灯片40
译者注记. 约定俗成地, 点号代表辖域尽可能向右延伸.

在实际情况下应用Scott的不动点归纳原理的难点在于识别出一个适切的可容许子集S, 即寻找一个具有合适强度的归纳假设.

第4.2节 例子

例子1.D是一个domain而f:(D×(D×D))D是一个连续函数. 令g:(D×D)(D×D)是由g(d1,d2)=def(f(d1,(d1,d2)),f(d1,(d2,d2))), 其中d1,d2D定义的连续函数. 那么, u1=u2, 其中(u1,u2)=deffix(g). (注意到之所以g是连续的, 是因为我们可以将其表达为复合, 投影和配对, 因而可以应用第3章第2节的命题1和幻灯片37: g=fπ1,π1,π2,fπ1,π2,π2.)
证明. 我们想要证明的是fix(g)Δ, 其中Δ=def{(d1,d2)D×D|d1=d2}.不难看出Δ是积domain D×D的一个可容许子集. 因此, 根据Scott不动点归纳原理, 我们只需要检验(d1,d2)D×D.(d1,d2)Δg(d1,d2)Δ其等价于(d1,d2)D×D.d1=d2f(d1,d1,d2)=f(d1,d2,d2)这显然为真.

接下来的例子表明Scott归纳原理对于证明关于程序的(指称版本的)部分正确性(partial correctness)断言来说很有用, 即具有形式如果程序终止, 那么对于结果来说这个那个的性质成立的断言. 与之形成对比的是, 完全正确性断言指的是程序的确会终止且对于结果来说这个那个的性质成立. 鉴于Scott归纳只能应用于这样的性质Φ, 其满足Φ()成立, 所以说它对于证明完全正确性不是很有用.

例子2.f:DD是幻灯片12上定义的连续函数, 其最小不动点是命令while X>0 do (YXY;XX1)的指称. 我们将会使用Scott归纳证明x,y0.fix(f)[Xx,Yy]fix(f)[Xx,Yy]=[X0,Y(!x)y]其中

第4.3节 构建链封闭子集

Scott归纳的威力依赖于我们有许多链封闭子集储备能用. 幸运的是, 我们可以根据构造方式来保证许多子集是链封闭的.

第4.3.1小节 基本关系

D是一个cpo. D×D的子集{(x,y)D×D|xy}{(x,y)D×D|x=y}都是链封闭的 (为什么?). 换言之, D×D上的性质 (或者说谓词) xyx=y都确定了链封闭集合.

译者注记. 对于D中的两个链x0x1x2y0y1y2, 如果对于每个n都有xnyn, 那么nxnnyn.
例子I: 最小前不动点性质

D是一个domain而f:DD是一个连续函数, 那么dD.f(d)dfix(f)d.以下是使用Scott归纳的证明.
证明.dDf的一个前不动点, 那么x(d)xdf(x)f(d)f(x)df(x)(d)因此, 我们有fix(f)(d).
幻灯片41
译者注记. 译者猜测这里使用而非的原因在于相当于断言为真. 另外, 幻灯片41有很多令译者感到奇怪的地方. 当然, 最奇怪的地方还是证明的命题是定义的一部分, 最小前不动点本来就应该小于其他不动点. 至于存在性之前读者已经看过证明了. 并且因为之前我们一起证明了最小前不动点和最小不动点均存在且相等, 所以说这里的Scott归纳的确也可以应用于最小前不动点. 不过, 实际上如果不看这个幻灯片的标题, 我们肯定会将fix(f)当成最小不动点. 而且, 证明的具体内容里本来就没有牵涉不动点和前不动点. 当然, 这是因为其被掩藏在了Scott归纳的抽象之下. 这个证明还有一些gap值得注意. 首先是(d)没有在书中任何地方得到定义, 不过按照格论的习惯其定义应该为(d){xD|xd}.其次, 这个证明未经验证地使用了所有(d)均为可容许子集这一事实. 不过, 这当然是显然的. 对于(d)中的任意链x0x1x2, 鉴于每个xnd, 故nxndnxn(d). 另外, 因为d, 所以(d).

第4.3.2小节 逆像和替换

f:DE是cpo DE之间的一个连续函数. 设SE的一个链封闭子集, 那么逆像f1(S)={xD|f(x)S}D的一个链封闭子集 (为什么?).

译者注记.SE的一个链封闭子集, 对于f1(S)中的链x0x1x2, 考虑其最小上界在f下的像f(nxn)我们希望其是S的一个元素, 而这实际上是显然的. 根据f的连续性, 我们知道f(nxn)=nf(xn)鉴于S是一个链封闭子集, 且对于每个n, f(xn)S, 故nf(xn)S也就是说, 我们有nxnf1(S)那么, 我们可以断言f1(S)是一个链封闭子集. 译注完毕.

设子集SE上的性质P所定义, 即S={yE|P(y)}那么f1(S)={xD|P(f(x))}也就是说, 若E上的性质P(y)确定了E的一个链封闭子集, 而f:DE是一个连续函数, 那么D上的性质P(f(x))确定了D的一个链封闭子集.

例子II

D是一个domain而f,g:DD是连续函数并且满足fggf, 那么f()g()fix(f)fix(g).以下是使用Scott归纳的证明.
证明. 考虑D的可容许性质Φ(x)(f(x)g(x))鉴于f(x)g(x)g(f(x))g(g(x))f(g(x))g(g(x))我们有f(fix(g))g(fix(g)).
幻灯片42
译者注记. 我们继续补齐一点gap. 鉴于g(fix(g))=fix(g)f(fix(g))fix(g)换言之, fix(g)f的一个前不动点. 然而fix(f)f的最小前不动点, 所以有fix(f)fix(g).

第4.3.3小节 逻辑运算

D是一个cpo. 令SDTDD的链封闭子集. 那么, 我们有STST都是链封闭子集 (为什么?). 若是基于性质的语言, 若P(x)Q(x)都确定了D的链封闭子集, 那么P(x)或者Q(x),P(x)&Q(x)也是如此.

如果Si,iI是由集合I索引的D的一个链封闭子集的族, 那么iISiD的一个链封闭子集 (为什么?).

译者注记. (不论有限还是无限的)交的情况比较简单, 并的情况比较有趣. 对于ST中的链x0x1x2, 我们可以按照是否属于S进行分类. 至少其中一类是无限的, 设其构成了(子)链y0y1y2. 我们知道nyn肯定是属于ST的, 若是能够证明nyn=nxn那么就结束了. 首先鉴于{y0,y1,}{x0,x1,}的一个子集, 所以nynnxn那么我们需要证明的是nxnnyn实际上对于任意的i, 鉴于子链y0y1y2的长度是无限的, 所以必然可以找到某个j使得xiyj, 那么可以看出nynx0x1x2的一个上界, 也就是说nxnnyn.说明完毕, 以下是正文.

因此, 如果一个性质P(x,y)确定了D×E的一个链封闭子集, 那么性质xD.P(x,y)确定了E的一个链封闭子集. 这是因为{yE|xD.P(x,y)}=dD{yE|P(d,y)}=dDfd1{(x,y)D×E|P(x,y)}其中fd:ED×E是连续函数, 定义为对于每个dD, fd(y)=(d,y).

实际上, 若称形式为f(x1,,xk)g(x1,,xl)f(x1,,xk)=g(x1,,xl)的性质为基本性质 (其中fg为连续函数), 那么对于由基本性质的合取与析取构成的东西进行其中一些变量的全称量化, 那么就会确定非量化的变量所对应的积cpo的一个链封闭子集.

译者注记.

不过, 注意到链封闭子集的无限并不必然是链封闭的; 有限子集总是链完备的, 但是其任意的并不是. 因此, 一般情况下我们不能使用存在量化构造链封闭子集.

第4.4节 练习

练习1.

第5章 PCF

语言PCF (Programming Computable Functions, 编程可计算函数) 是一个简单的函数式编程语言, 其经常用作指称语义和操作语义的理论建立中的示例语言, 也包括这两种语义之间的关系的理论. 其句法是由Dana Scott于大约1969年引入的, 作为Logic of Computable Functions (可计算函数逻辑)的一部分, 其也在具有高度影响力的论文Plotkin (1977) 里作为一种编程语言被研究.

本章将给出我们在这个讲义里所使用的PCF的某个特定版本的句法和操作语义. 而在第6章中我们将看到如何使用domain和连续函数来赋予它一个指称语义.

第5.1节 项和类型

PCF语言的类型, 表达式, 在幻灯片43中定义.

PCF句法

类型τnat|bool|ττ表达式M0|succ(M)|pred(M)|true|false|zero(M)|x|if M then M else M|fn x:τ.M|MM|fix(M)其中x𝕍, 一个变量无限集合.
技术细节: 我们在绑定变量的α变换的意义下将表达式视为等同的, 而绑定变量是由fn表达式构造子创建的: 根据定义一个PCF是一个表达式的α等价类.
幻灯片43

各种句法形式的意义如下.

第6章 PCF的指称语义

第7章 将指称语义和操作语义联系起来

第8章 完全抽象