第 2 章 可计算函数程序设计语言

94
第2第 第第第第第第第第第第第 第第第第第第第第第第第第第第第 PCF 第第第第第第第第第第第第第第第第第第第第第 第第第第第第第第第 第第

Upload: louisa

Post on 20-Mar-2016

182 views

Category:

Documents


2 download

DESCRIPTION

第 2 章 可计算函数程序设计语言. 介绍基于类型化  演算的函数式语言 PCF 。 该语言的设计目的是便于后面各章的分析和讨论,而不是把它作为实际语言。. 2.1 引 言. 主要议题如下 通过例子来介绍类型化  演算及基于它的语言的语法和语义 用不动点算子来处理函数的递归定义 讨论 PCF 的 公理语义、操作语义和指称语义 一些基本的编程方法都可以用 PCF 来实现 用操作语义来研究 PCF 的表达能力和局限 介绍 PCF 的 一些扩充和衍生. 2.2 语 法. 2.2.1 概述 由列出 PCF 的类型来概括其构造 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第 2 章  可计算函数程序设计语言

第 2 章 可计算函数程序设计语言• 介绍基于类型化演算的函数式语言 PCF 。• 该语言的设计目的是便于后面各章的分析和讨论,而不是把它作为实际语言。

Page 2: 第 2 章  可计算函数程序设计语言

2.1 引 言主要议题如下• 通过例子来介绍类型化演算及基于它的语言的语法和语义•用不动点算子来处理函数的递归定义•讨论 PCF 的公理语义、操作语义和指称语义•一些基本的编程方法都可以用 PCF 来实现•用操作语义来研究 PCF的表达能力和局限•介绍 PCF 的一些扩充和衍生

Page 3: 第 2 章  可计算函数程序设计语言

2.2 语 法2.2.1 概述由列出 PCF 的类型来概括其构造• 基本类型: nat 和 bool• 类型构造符

– 笛卡儿积– 函数类型

• 规定:右结合,的优先级高于 等同于 () 等同于 ()

Page 4: 第 2 章  可计算函数程序设计语言

2.2 语 法2.2.2 布尔值和自然数• 布尔类型常量: true , false• 布尔类型条件表达式– if bool_exp then bool_exp else bool_exp

• 自然数类型常量 0,1, 2,3, … , (数码 )• 自然数类型条件表达式– if bool_exp then nat_exp else nat_exp

• 自然数相等测试– Eq? , 如 Eq? 5 0 false

Page 5: 第 2 章  可计算函数程序设计语言

2.2 语 法例 : if bool_exp then x : nat.M else x :

nat.N _exp :: = … | if bool_exp then _exp

else _exp • 尚未列出 PCF 自然数类型和布尔类型的全部表达式

Page 6: 第 2 章  可计算函数程序设计语言

2.2 语 法自然数类型和布尔类型的等式公理• 0 + 0 = 0, 0 + 1 1, …, 1 + 0 = 1, 1 + 1 = 2, … • 与条件表达式有关的公理模式– if true then M else N = M– if false then M else N = N

• 相等测试也有无数个公理,其形式如下:• 对任意数码 n , Eq? n n = true• 对任意不相同数码 m,n , Eq? m n = false• 没有等式公理 Eq? M M = true

Page 7: 第 2 章  可计算函数程序设计语言

2.2 语 法• 操作语义由一组归约公理来定义,把每个等式公理自左向右定向可得到对应的归约公理 ,归约公理通常用来计算表达式• 可归约式:匹配一个归约公理左部的项• 例: if Eq? (6 +6) 7 then (2+2) else 36 if Eq? 12 7 then (2 + 2) else 36 if false then (2 + 2) else 36 36

Page 8: 第 2 章  可计算函数程序设计语言

2.2 语 法2.2.3 二元组和函数有序对(也称二元组) , 笛卡儿积类型 M, N : • 射影操作 – Proj1 : 和 Proj2 :

• 等式公理– Proj1M, N = M 和 Proj2M, N = N (proj) (Proj1P), (Proj2P) = P ( 满 射 配对, sp )

Page 9: 第 2 章  可计算函数程序设计语言

2.2 语 法• 满射配对对显式二元组是多余的

(Proj1M, N), (Proj2M, N ) = M, (Proj2M, N ) = M, N

• 但是没有这个公理不可能证明 (Proj1x), (Proj2x) = x

Page 10: 第 2 章  可计算函数程序设计语言

2.2 语 法• 二元组的归约规则可以由将 proj 公理从左到右定向得到• 没有 sp 归约规则

– 它不是非要不可– 当和函数的递归定义合在一起时,该规则会导致合流性的失败

Page 11: 第 2 章  可计算函数程序设计语言

2.2 语 法函数• PCF 函数由抽象表示• 任何 PCF 类型可以作为 PCF 函数的论域或值域• 例

comp =def f : natnat.g : natnat.x : nat. f (gx)add =def p : nat nat.(Proj1 p) + (Proj2 p)

Page 12: 第 2 章  可计算函数程序设计语言

2.2 语 法类型化表达式的代换的精确定义• [N/x ]x = N• [N/x ] = ,对 x 的变量和常量• [N/x ](P Q ) = ([N/x ]P ) ([N/x ]Q )• [N/x ]x : . M = x : . M• [N/x ]y : . M = y : .[N/x ] M ,只要 x

y 并且 yFV(N)• [N/x ]y : . M = (z : .[N/x ][z/y ] M) ,其

中 zFV(M N) 并且 y, z x• 加上加法和条件算符等后,代换可拓广

[N / x ](P + Q ) = ([N / x ]P ) + ([N / x ]Q )

Page 13: 第 2 章  可计算函数程序设计语言

2.2 语 法函数的等式公理 x :.M =y :.[y/x]M , y 在 M 中不是自由的 () • (x :.M )N =[N/x]M () x : . Mx = M , x 在 M 中不是自由的 () 公理对显式函数表达式也是冗余的– 如果 M 有 y : .P 的形式,并且 x 在 M 中不是自由的,可以用公理证明 x : . Mx = M– 如果 M 是函数类型的变量,没有公理不可能证明 x : . Mx = M

Page 14: 第 2 章  可计算函数程序设计语言

2.2 语 法函数的归约公理• 仅把公理定向为从左到右的归约规则 归约用于演算的许多版本中

Page 15: 第 2 章  可计算函数程序设计语言

2.2 语 法curry 算子将多元函数变换成高阶函数Curry = def f : nat nat nat.x : nat.y : nat.f x, y

Curry(add) (f : nat nat nat.x : nat.y : nat.f x, y) add

= x : nat. y : nat.add x, y x : nat. y : nat.(p : nat nat.(Proj1 p) +

(Proj2 p)) x, y = x : nat. y : nat. Proj1x, y + Proj2 x, y = x : nat. y : nat.x + y

Page 16: 第 2 章  可计算函数程序设计语言

2.2 语 法2.2.4 声明和语法美化 演算可作为程序设计的一种模型语言

begin function f (x : nat) : nat; return x; end;

bodyend

• 对应的表达式(f : nat nat . body) (x : nat.x)

Page 17: 第 2 章  可计算函数程序设计语言

2.2 语 法• let 声明

let x : = M in N在声明体 N 中, x 被约束到 M• 把 let 看成一种缩写,或者称为“语法美化” • 可以在 PCF 表达式中使用 let ,但又不把它看成 PCF 真正语法的一部分• let x : = M in N =def (x : .N)M • 不需要规定任何有关 let 的额外的等式公理和归约规则

Page 18: 第 2 章  可计算函数程序设计语言

2.2 语 法例:let compose : (nat nat) (nat nat) nat nat = f : nat nat.g : nat nat.x : nat.f(gx) in

let h : nat nat = x : nat.x + x incompose h h 5翻译成纯 PCF 表达式:

(compose : (nat nat) (nat nat) nat nat. (h : nat nat. compose h h 5) x : nat.x + x) f : nat nat.g : nat nat.x : nat.f(gx)

Page 19: 第 2 章  可计算函数程序设计语言

2.2 语 法(compose : (nat nat) (nat nat) nat nat.

(h : nat nat. compose h h 5) x : nat.x + x) f : nat nat.g : nat nat.x : nat.f(gx)

(h : nat nat.(f : nat nat.g : nat nat.x : nat.f (gx))h h 5) (x : nat.x + x)

(f : nat nat.g : nat nat.x : nat.f(gx)) (x : nat.x + x) (x : nat.x + x) 5

(x : nat.x + x) ((x : nat.x + x) 5) ((x : nat.x + x) 5) + ((x : nat.x + x) 5) (5 + 5) + (5 + 5) 20

Page 20: 第 2 章  可计算函数程序设计语言

2.2 语 法另一种语法扩充let f (x : ) : = M in N =def let f : =x : .M in N

Page 21: 第 2 章  可计算函数程序设计语言

2.2 语 法2.2.5 递归函数和不动点算子将递归函数定义看成 let 和一种新的基本函数的组合• 递归使得表达式可能没有范式• 选择哪个归约成为一件重要的事,因为有的选择会导致归约不终止• 递归函数的声明

letrec f : = M in N• 例: letrec f : nat nat =y : nat.(if Eq? y

0 then 1 else y f (y – 1)) in f 5 ( 阶乘函数 )

Page 22: 第 2 章  可计算函数程序设计语言

2.2 语 法• 把整个等式看成一个关于 f 的方程

f : nat nat = y : nat.if Eq? y 0 then 1 else y f (y

– 1)• 让表达式中 f 5 中的 f 指称该方程的一个解• 把求解递归定义的等式转化为求高阶函数的不动点

Page 23: 第 2 章  可计算函数程序设计语言

2.2 语 法• 如果 F : 是某类型到它自己的函数,那么 F 的不动点是使得 F (x) = x 的值 x : – 自然数上平方函数的不动点有 0 和 1– 恒等函数有无数个不动点– 后继函数没有不动点

• 阶乘函数是方程 (f : nat nat = y : nat.if Eq? y 0 then 1 else y f (y – 1) ) 的解• 阶乘函数是F =def f : nat nat.y : nat.if Eq? y 0 then 1 else

y f (y – 1)的不动点

Page 24: 第 2 章  可计算函数程序设计语言

2.2 语 法不动点算子• fix : ( ) , 对每个类型• 函数 fix为 到 的函数产生一个不动点• 把 letrec 看成是 let 和不动点算子组合的美化 – letrec f : M in N

=def let f : = (fix f : . M) in N• fix : ( ) 的等式公理– fix = f : .f (fix f ) (fix)– fix MM (fix M) (使用 ( ) 可得)

• (fix) 归约规则– fix f : .f (fix f )

Page 25: 第 2 章  可计算函数程序设计语言

2.2 语 法继续阶乘函数的例子– F =def f : nat nat.y : nat.if Eq? y 0 then 1 else y

f (y – 1)– fact =def fixnatnatF

– fact n (fix F) n F (fix F) n (f : nat nat. y : nat.if Eq? y 0 then 1 else y f (y – 1)) (fix F) n if Eq? n 0 then 1 else n (fix F) (n-1)

– 对任何自然数 n ,最终得到 fact n = n!

Page 26: 第 2 章  可计算函数程序设计语言

2.3 程序和语义2.3.1 程序和结果• PCF 语言有两个语法范畴:类型和项• 可观测的类型:自然数类型和布尔类型

– 像 nat nat 这样的函数类型不是可观测的类型• 程序: PCF 语言中合式的、可观测类型的闭项

– 进一步限制:“不需要加输入和输出的程序”• 结果:计算或执行程序的可观测的效果(可观测类型的闭范式)• 语言语义的一般定义:程序集合和结果集合之间的一种关系

Page 27: 第 2 章  可计算函数程序设计语言

2.3 程序和语义2.3.2 公理语义• 公理语义是一个证明系统,用它可以推导程序及其组成部分的性质• 这些性质可以是等式、给定输入下有关程序输出的断言、或其它性质• 注意力放在等式公理语义上• 两个程序在一个公理语义中等价,只要为它们推导出来的断言正好完全相同

Page 28: 第 2 章  可计算函数程序设计语言

2.3 程序和语义公理• 自反(ref) M = M• 基本类型 nat 和 bool(add) 0 + 0 = 0, 0 + 1 = 1, … , 3 + 5 = 8, …(Eq?) Eq? n n = true, Eq? n m = false

( n 和 m 是不同的数码)(cond) if true then M else N = M,

if false then M else N = N• 二元组(proj) Proj1 M, N = M Proj2 M, N = N(sp) Proj1 P, Proj2 P = P• 重新命名约束变量( ) x : .M = y : .yxM , y 在 M 中不是自由的

Page 29: 第 2 章  可计算函数程序设计语言

2.3 程序和语义公理• 函数( ) (x : .M)N = N/xM( ) x : .Mx = M , x 在 M 中不是自由的• 递归(fix) fix = f : .f (fix f)

Page 30: 第 2 章  可计算函数程序设计语言

2.3 程序和语义推理规则• 等价(sym),(trans)

• 同余nat 和 bool

M = NN = M

M = N, N = PM = P

M = N, P = QM+P = N+Q

M = N, P = QEQ? MP = EQ? NQ

M1 = M2, N1 = N2, P1 = P2

if M1 then N1 else P1 = if M2 then N2 else P2

Page 31: 第 2 章  可计算函数程序设计语言

2.3 程序和语义二元组

函数

M = NProji M = Proji N

M = N, P = QM, P = N, Q

M = Nx:. M = x:. N

M = N, P = QM P = N Q

Page 32: 第 2 章  可计算函数程序设计语言

2.3 程序和语义• 除了抽象和应用外,其它同余规则都是多余的• 例:针对 + 的同余规则是多余的

– 假定 M=N 和 P=Q– 由自反公理,有等式x : nat.y : nat.x y = x : nat.y : nat.x y– 由应用的同余规则可得 (x:nat.y:nat.x y)M = (x:nat.y:nat.x y)N – 由公理模式和传递性可得y : nat.M y = y : nat.N y

– 再次使用公理模式和传递性可得M P = N Q

Page 33: 第 2 章  可计算函数程序设计语言

2.3 程序和语义• 该公理语义强到足以确定程序的含义• 该系统证明不了加法是可交换的,也证明不了递归函数间的许多有意义的等价• 对于这些性质需要用归纳法来证明• PCF 语言对类型并不需要证明系统,因为两个类型相同当且仅当它们在语法上相同

Page 34: 第 2 章  可计算函数程序设计语言

2.3 程序和语义2.3.3 指称语义概述 PCF 的指称语义,以便三种语义形式可以比较• 为每个类型选择一个值集来给出项的指称• nat 的语义论域是自然数值集 N {nat}– letrec f (x : nat ) : nat = f (x + 1) in f (0) 计算不终止

• bool 的语义论域是布尔值集 B {nat}• nat 和 bool 类型的任何项指派相应语义论域上的一个值,也称为它们的语义解释

Page 35: 第 2 章  可计算函数程序设计语言

2.3 程序和语义• 积类型 的数学值是有序对集合• 函数类型的数学值是从 到 的函数集合

– 如果 = ,那么函数有不动点• 约定:对任何 nN ,用⌈ n⌉ 表示其数码 • 例: x : nat.M

如果对任何自然数 nN, 都有[⌈n⌉ / x]M ⌈f (n)⌉

那么 x : nat.M 的指称就是数值函数 f : NN

Page 36: 第 2 章  可计算函数程序设计语言

2.3 程序和语义• 环境是指从变量到值的映射– 若 x :, (x) 是类型 的值集上的元素

• 通过归纳可以定义表达式 M 在环境 中的含义〖 M 〗• 〖 x 〗是变量 x 在环境中的值• 函数应用〖 MN 〗的含义是通过把 M 指称的函数〖 M 〗应用到 N 指称的变元

〖 N 〗来获得

Page 37: 第 2 章  可计算函数程序设计语言

2.3 程序和语义• 指称语义是可合成的,即任何表达式的含义由它子表达式的含义决定– 如果〖 B 〗 是 true ,那么〖 if B then M else N 〗 = 〖 M 〗– 如果〖 B 〗是 false ,那么〖 if B then M else N 〗 = 〖 N 〗– 否则,〖 if B then M else N 〗 =

• 如果 B, M和 N同 B , M 和 N 分别有同样的指称,那么〖 if B then M else N 〗 = if B then M else N 〗

Page 38: 第 2 章  可计算函数程序设计语言

2.3 程序和语义2.3.4 操作语义• eval (M) = N 当且仅当经若干步(含零步)归约, M 可以归约到范式 N类型 nat 和 bool(add) 0 + 0 0, 0 +1 1, … ,

3 + 5 8, …(Eq?) Eq? n n true, Eq? n m false

n 和 m 是不同的数码(cond ) if true then M else N M

if false then M else N N

Page 39: 第 2 章  可计算函数程序设计语言

2.3 程序和语义二元组(proj) Proj1 M, N M Proj2 M, N N

重新命名约束变量( ) x : .M = y : .yxM

y 在 M 中不是自由的函数( )(x : .M)N N/xM递归(fix) fix f : .f (fix f)

Page 40: 第 2 章  可计算函数程序设计语言

2.3 程序和语义• 这个操作语义并没有指定计算步骤,因而显得抽象一些• 保留了重新命名约束变量的等式公理的形式• 对于二元组的满射配对公理 (sp) 和函数的外延公理 () ,没有相应的归约规则

Page 41: 第 2 章  可计算函数程序设计语言

2.3 程序和语义2.3.5 由各种形式的语义定义的等价关系• 各种等价关系– 公理等价: M = N 是可证明的

用 M =ax N 表示– 指称等价: M 和 N 对自由变量的任何取值都有相同的指称

用 M =den N 表示– 操作等价: eval(M ) ≃ eval (N ) (程序 M 和 N计算到同样结果,或者它们的计算都没有定义 )

用 M =op N 表示

Page 42: 第 2 章  可计算函数程序设计语言

2.3 程序和语义• 操作等价M =op N 可以从程序推广到一般项– 上下文 C[ ] 是一个项,但其中有一个洞– 例: C0[ ] =def x : nat.x + [ ]

– 例: C0[x] 是 x : nat.x + x– 项 M 和 N 操作等价:

如果对任意使得 C[ M ] 和 C[ N ]都是程序的上下文 C[ ] ,都有 eval (C[ M ] ) ≃ eval (C[ N ] )

Page 43: 第 2 章  可计算函数程序设计语言

2.3 程序和语义• 等式证明系统的可靠性:

如果在公理语义中能证明 M 和 N 相等,那么在指称语义中, M 和 N 应该有同样的含义• =ax =den

• 这是判断公理系统正确性的基本标准• 对 PCF 语言而言,公理语义对指称语义是可靠的

Page 44: 第 2 章  可计算函数程序设计语言

2.3 程序和语义• 操作语义的计算适当性

– 如果 M 是个程序,并且 M 和作为结果的 N 有同样的指称,那么在操作语义中,执行程序 M的结果是 N– 计算适当性表明已有足够的归约规则去确定任何程序的值– 对 PCF 语言而言,操作语义有计算的适当性

Page 45: 第 2 章  可计算函数程序设计语言

2.3 程序和语义• 对 PCF 语言的程序而言,要满足的最小要求是– (programs M ) (results N ) M =ax N iff M =den

N iff M =op N

• 对任意的项,希望满足的要求是– =ax =den =op

• 操作等价是三者中最粗糙的一个,和指称等价或可证明的等价相比,可能有更多的项操作等价• 若 =op =ax ,可能会出现不一致的证明系统

Page 46: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器• 本节讨论基于操作语义的 PCF 程序的执行• 已经讨论的操作语义是不确定的符号解释器• 本节讨论其它形式的符号解释器

– 确定的:急切归约、最左归约、惰性归约– 并行归约

Page 47: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器2.4.1 归约的合流性每当 M N1 并且 M N2 ,那么存在项 P ,使得 N1 P 并且 N2 P

• PCF 归约是合流的• 合流性也叫做 Church-Rosser 性质

M

N2N1

P

Page 48: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器如果由一组等式公理定向确定• 如果 M N ,那么可以证明等式 M = N• 从 M N 和 P N ,可以证明 M

P• 合流隐含着,一个等式是可证明的当且仅当它的两个项都可以归约到一个公共项• 如果两个不同的项都不能归约,那么不可能证明它们相等

Page 49: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器例: letrec f (x : nat) : nat = if Eq? x 0 then 0 else x +

f(x - 1) in f 2• F =def f : nat nat. x : nat. if Eq? x 0 then 0 else x

+ f (x - 1)• (fix F)2 (f : nat nat. x : nat. if Eq? x 0

then 0 else x + f (x - 1)) (fix F)2 if Eq? 2 0 then 0 else 2 + (fix F) 1 2 + if Eq? 1 0 then 0 else 1 + (fix F) 0 2 + 1 + (fix F) 0 2 + 1 + 0 3

Page 50: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器例:这种形式的程序执行和大家熟悉的方式略有点区别• let f (x : nat) : nat = 5 in

letrec g (x : nat) : nat = g (x + x) in f (g 3)

• 在大多数程序设计语言中,该程序不会终止

Page 51: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器2.4.2 归约策略• 归约策略:项到项的部分函数 F ,如果 F

(M) = N ,那么 MN • 与归约策略 F 对应的部分计算函数 evalF :

PCF PCF 是:evalF (M) =

if F(M) is not defined then Melse if F(M) = M and evalF (M) = N then N

• evalF 在数学上等价于遵循策略 F逐步进行归约,直到该策略不能再遵循为止。

Page 52: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器• 感兴趣的是一步归约策略

– 只要有可能便选择一步归约的策略– 程序 M 的计算 eval(M) 是 M 的范式或者 eval(M)没有定义– 基于项本身的形式来选择一步归约

• 先“优化”函数 x : .M • 最左归约(惰性归约)• 急切归约

(x : .M)N

(x : .M)N (x : .M)N[N/x]M

Page 53: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器2.4.3 最左归约和惰性归约• 最左归约:对项中尽可能左边的符号进行归约

– 遵循的是结构化操作语义的风格– 每条规则正好作用到一种形式的项– 考察项的结构就知道该用哪条规则

Page 54: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器例( (x : nat.y : nat.x + y) 9) 7 + (x : nat.x) 5left (y : nat.9+ y) 7 + (x : nat.x) 5left (9 + 7 ) + (x : nat.x) 5left 16 + (x : nat.x) 5left 16 + 5left 21

Page 55: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器例(x : nat.y : nat.x + y) ( (z : nat.z) 20)left y : nat.( (z : nat.z) 20) + y

left y : nat.20 + y

Page 56: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器PCF 的最左归约• 公理

M N 是归约公理• 子项规则

nat 和 bool

N 是范式

M left M

M + N left M + N

M NM left N

M left M

N + M left N + M

Page 57: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器

N 是 范式

M left M

Eq? M N left Eq? M N

M left M

Eq? N M left Eq? N M

Page 58: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器

M 是范式

M,N 是范式

M left M

if M then N else P left if M then N else P

N left N

if M then N else P left if M then N else P

P left P

if M then N else P left if M then N else P

Page 59: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器二元组

M 是 范式

M left M

M, N left M, N

N left N

M, N left M, N

M left M

Proji M left Proji M

Page 60: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器函数

M 是 范式

M left M

M N left M N

N left N

M N left M N

M left M

x : . M left x : . M

Page 61: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器• 命题 令 M 是任意类型的 PCF 项。那么对任何范式 N , M left N 当且仅当 M N 。• 命题 令 M 是 任 意 类 型 的 PCF 项 。 那 么

evelleft(M) = N 当且仅当 M N 并且 N 是范式。 • 如果仅要求这两个命题对 PCF 程序(而不是所有的项)成立,可以采用惰性归约。• 不能再进行惰性归约的项叫做惰性范式。 nat

和 bool 的惰性范式正是它们的范式 • 在实际实现中惰性归约比最左归约用得更普遍。

Page 62: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器PCF 的惰性归约• 公理

M N 是归约公理• 子项规则

nat 和 bool

n 是数码

M lazy M

M + N lazy M + N

M NM lazy N

M lazy M

n + M lazy n + M

Page 63: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器

n 是 数码

M lazy M

Eq? M N lazy Eq? M N

M lazy M

Eq? n M lazy Eq? n M

Page 64: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器

下面两条规则不再需要

M 是范式 M,N 是范式

M lazy M

if M then N else P lazy if M then N else P

N left N

if M then N else P left if M then N else P

P left P

if M then N else P left if M then N else P

Page 65: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器二元组前两条规则不再需要

M 是 范式

M left M

M, N left M, N N left N

M, N left M, N M lazy M

Proji M lazy Proji M

Page 66: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器函数

下 面 两 条 规 则 不再需 要

M 是 范式

M lazy M

M N lazy M N

N left N

M N left M N M left M

x : . M left x : . M

Page 67: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器• 命题 如果 M 是 PCF 闭项,但它不是 x : .M1 或 M1, M2 的形 式 ,那 么 对 任何 项N , M lazy N 当且仅当 M left N 。

• 推论 如果 P 是 PCF 程序, R 是结果,那么P lazy R 当且仅当 P left R 。

• 和最左归约相比,由于惰性归约的规则集合小一些,因此有可能得到一个效率相对较高的实现。

Page 68: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器2.4.4 并行归约• 对 PCF 来说,当能独立地归约两个子表达式中的任意一个时,就应该可以同时归约它们

M NM N

M1 N1, …, Mk Nk

C[M1, …, Mk] C[N1, …, Nk]

Page 69: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器并行归约的特点• 在 PCF 中, M N 当且仅当 M N• 并行归约可以较快到达范式

Page 70: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器2.4.5 急切归约• 最左归约和 PCF 的公理语义一致,并且允许不确定地或并行地实现• 更通常的次序是急切归约,它和 PCF 的公理语义不一致• let f (x : nat) : nat = 5 in

letrec g (x : nat) : nat = g (x + x) in f (g 3)

Page 71: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器• 值:指不能再进行急切归约的项,即已经完全计算了的项• 常量、变量和抽象都是值,值的二元组也是值• 二元组中至少有一元不是值的情况,还有函数应用都不能称为值• 急切归约与其它归约策略的主要区别– 只有当函数变元是值时才能使用 归约,只有当二元组的两个元素都是值时才能使用 Proji 归约。– fix 归约也不同,它会暂停 fix 作用于其变元的归约

Page 72: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器值• 如果 V 是常量、变量、抽象或值的二元组,那么 V 是一个值• delay M =def x : .Mx

x 在 M : 中不是自由的公理• (x : .M)V eager VxM V 是值• Proji(V1,V2) eager Vi V1,V2 是值• fixV eager V(delay fixV ) V 是值

Page 73: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器• 0 + 0 eager 0, 0 +1 eager 1, …, 3 + 5 eager 8,

… • Eq? n n eager true, Eq? n m eager false

n, m 是不同的数码• if true then M else N eager M

if false then M else N eager N x : .M = y : .yxM , y 在 M 中不是自由的

Page 74: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器• 子项规则

nat

n 是数码

M eager M

M + N eager M + NM eager M

n + M eager n + M

Page 75: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器bool

n 是 数码

M eager M

Eq? M N eager Eq? M N

M left M

Eq? n M left Eq? n M

M eager M

if M then N else P eager if M then N else P

Page 76: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器二元组

V 是值

M eager M

M, N eager M, N

N eager N

V, N eager V, N

M eager M

Proji M eager Proji M

Page 77: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器函数

V 是值下面一条规则不再需要

M eager M

M N eager M N

N eager N

V N eager V N

M left M

x : . M left x : . M

Page 78: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器(fix (x : nat nat.y : nat.y)) ((z : nat.z +1) 2)

(fix (x : nat nat.y : nat.y))eager (x : nat nat.y : nat. y)

(delay fix (x : nat nat.y : nat. y))eager y : nat. y

(z : nat.z +1) 2 eager 2 + 1 eager 3整个项变成了 (y : nat. y) 3 ,归约到 3

Page 79: 第 2 章  可计算函数程序设计语言

2.4 归约和符号解释器• 急切归约会发散的例子

let f (x : nat) : nat = 5 inletrec g (x : nat) : nat = g (x +1) in f (g 3)

• 在实际中用急切计算而不是用最左计算的主要原因– 最左归约的实现通常是低效的。当像 f x 这样的变元传给函数 g 时( g(fx) ),必须传递 f 的代码的指针并记住适当的词法环境。– 最左归约和赋值的组合令人混淆,副作用的出现使得最左计算与不确定计算和并行计算不一致

Page 80: 第 2 章  可计算函数程序设计语言

2.5 程序设计实例、表达能力和局限2.5.1 记录和 n 元组• 记录是多个成分的聚集,每个成分有不同的标记• 记录的类型写成 l1 : 1, …, l k : k

• 记录写成 l1 = M1, …, l k = Mk

• 记录 r 中的成分 li 的选择可用加点的记号 r.li来表示• 等式公理

l1 = M1, …, l k = Mk .li = Mi

Page 81: 第 2 章  可计算函数程序设计语言

2.5 程序设计实例、表达能力和局限• 使用记录的优点

– 一个方便之处是其成分次序无关紧要– 另一个优点是,可以选择助记忆的名字作为标记

• 记录和记录类型可以翻译成 PCF 的二元组和笛卡儿积• 为了简化 n 个成分的记录到 PCF 的翻译,可以定义 n 元组作为一种语法美化

Page 82: 第 2 章  可计算函数程序设计语言

2.5 程序设计实例、表达能力和局限• 引入 n 元积记号

1 … n =def 1 (2 … (n-1 n) … )

• 引入 n 元组记号M1, … , Mn =def M1, M2, … Mn-1, Mn …

• 很容易检查,如果 Mi : i ,那么M1, … , Mn : 1 … n

• 取 n 元组的成分 =def x:1 … n .Proj1( x) (i < n)

=def x:1 … n .( x)

1 … nProjii - 1Proj2

1 … nProjnn - 1Proj2

Page 83: 第 2 章  可计算函数程序设计语言

2.5 程序设计实例、表达能力和局限• 使用 n 元组,可以把多于两个成分的记录翻译

成 PCF 表达式 l1 : 1 , … , l k : k =def 1 … k

l1 = M1 , … , l k = Mk =def M1, … , M k

– M.li =def M

• 例: let r : A : int, B : bool = A = 5, B = false in if r.B then r.A else r.A + 1去掉记录的语法美化,得到:let r : int bool = 5, false in if Proj2 r then Proj1 r else (Proj1 r)+1

1 … nProji

Page 84: 第 2 章  可计算函数程序设计语言

2.5 程序设计实例、表达能力和局限2.5.6 并行运算的不可定义性并行或• 计算 M ∨ N 的方式是:并行地归约 M 和

N ,如果其中一个终止且值为 true ,那么另一个计算流产,并返回 true• 否则继续归约它们,希望它们都能归约到范式

Page 85: 第 2 章  可计算函数程序设计语言

2.5 程序设计实例、表达能力和局限并行或是不能由 PCF 定义的• 定理 不存在 PCF 表达式 POR ,它对任意的闭布尔表达式 M 和 N 有下面的行为– POR M N true ,

如 果 M true 或 N true ;

– POR M N false ,如果 M false 并且 N

false ;– POR M N 没有范式 否则。

Page 86: 第 2 章  可计算函数程序设计语言

2.6 衍生和扩充2.6.1 单元类型与和类型• 单元类型 unit :只有一个元素的类型– unit 类型的常量:– unit 类 型 的 等 式 公 理 : M:unit ( 对 任 何

M:unit)– unit 类型的归约公理: M :unit

• 单元类型好象没有什么意义,但是当它同和类型及其它形式的类型组合起来时,显得非常有用。

Page 87: 第 2 章  可计算函数程序设计语言

2.6 衍生和扩充• 和类型 : 类型和的可区分的并– 可区分的并:例如,如果取 int 和 int 的并集,得到的仍然是 int;但是, int 和 int 的可区分的并

有 int 的两个“拷贝” – 内射函数

Inleft, : Inright, :

– 分情况函数Case, , : ( +) ( ) ( )

Page 88: 第 2 章  可计算函数程序设计语言

2.6 衍生和扩充• 和类型的等式公理

(记住 Case, , : ( +) ( ) ( ) )– Case, , (Inleft, x) f g = f x– Case, , (Inright, x) f g = g x– 外延公理

Case, , x (f o Inleft, ) (f o Inright, ) = f x其中 f : ( +) ( +)

• 和类型的归约公理– Case, , (Inleft, x) f g f x– Case, , (Inright, x) f g g x

Page 89: 第 2 章  可计算函数程序设计语言

2.6 衍生和扩充• 单元类型与和类型加入 PCF 后, bool 可以省略– bool =def unit + unit– true =def Inleft – false =def Inright – if M then N else P =def

Caseunit, unit, M (K, unit N) (K, unit P)其中 N, P : 并且 K, unit 是项 x :.y : unit.x

– 可以检验下面两个公理if true then M else N = Mif false then M else N = N

Page 90: 第 2 章  可计算函数程序设计语言

2.6 衍生和扩充2.6.2 递归类型• 类型等式 t = ,其中 t 出现在中• 也可以为递归定义的类型引入不动点算子,并且用 fix (t.) 表示方程 t = 的一个解• 用 t.作为 fix (t.) 的语法美化• 在 t. 中约束 t ,因此在类型表达式中既可以有约束变量也可以有自由变量• 没有任何项构造可以约束类型变量,在项中仅使用闭类型。若类型表达式含自由变量的话,会导致多态性

Page 91: 第 2 章  可计算函数程序设计语言

2.6 衍生和扩充• 若把 PCF 中 nat 和 bool 类型删除 , 把单元类型、和类型及递归类型加入, PCF 的类型表达式则是由文法

::= t | unit | + | | | t.产生的闭表达式

• 有递归类型时,需要仔细考虑类型相等问题

Page 92: 第 2 章  可计算函数程序设计语言

2.6 衍生和扩充• 等式 t = 意味着 fix (t.) = fix (t.) t

用记号表示为 t. = t. t • 对类型等式 t. = t. t 有两种不同的观点

– 等式左右两边是真正不可区分的类型– 等式左右两边是同构的类型

t. t. t

Page 93: 第 2 章  可计算函数程序设计语言

2.6 衍生和扩充• nat 作为递归类型的定义

– 自然数的一个显著特征是,如果加一个元素到自然数集合,所得到的集合和自然数集合同构– unit 比多一个元素,因此– nat unit + nat ,即 nat =def t.unit + t– nat unit + nat unit + (unit + nat) …

unit +(unit +(unit +(unit +(unit + … +nat )…) ) )• PCF 表达式翻译到只含递归的类型定义、单元类型与和类型的表达式

Page 94: 第 2 章  可计算函数程序设计语言

习 题 第一次: 2.3 , 2.4第二次: 2.7 , 2.11 , 2.14第三次: 2.19 , 2.20 , 2.26第四次: 2.34