910 likes | 1.12k Views
指称语义简介. 西安电子科技大学 软件工程研究所 刘 坚. 形式化语义(动态语义). 语义的形式化描述(形式化语义)对程序设计语言的设计与实现均具有重要意义; 形式化语义从数学的角度 ( 用数学的方法 ) 研究程序设计语言的语义 ( 最初也被称为数学语义 ) ,使得: 全面、准确了解 ( 规定 ) 程序设计语言的语义 预测程序的行为 对程序进行推理 ( 如一程序与另一程序是否相等 ) 形式化语义的应用 语义设计 程序验证 程序自动生成 ( 编译器自动构造 ) 形式化描述语义的方法 操作语义 公理语义 指称语义. 指称语义.
E N D
指称语义简介 西安电子科技大学 软件工程研究所刘 坚
形式化语义(动态语义) • 语义的形式化描述(形式化语义)对程序设计语言的设计与实现均具有重要意义; • 形式化语义从数学的角度(用数学的方法)研究程序设计语言的语义(最初也被称为数学语义),使得: • 全面、准确了解(规定)程序设计语言的语义 • 预测程序的行为 • 对程序进行推理(如一程序与另一程序是否相等) • 形式化语义的应用 • 语义设计 • 程序验证 • 程序自动生成(编译器自动构造) • 形式化描述语义的方法 • 操作语义 • 公理语义 • 指称语义
指称语义 • 赋予程序的每个短语(如每个表达式、命令、声明等)意义 ,即将语言的语义结构强加给对应的语法结构; • 每个短语的意义由它的子短语来定义; • 每个短语的意义被称为指称,从而发展出指称语义 。 • 本章内容 • 指称语义的基本概念; • 指称语义的基本技术:如何用指称语义描述程序设计语言的特性,如存贮、环境、抽象与参数、原子类型与组合类型、以及失败等。 本节内容 指称语义的基本概念:短语、指称、域、语义函数、函数定义的符号表示等。
1.1 语义函数 语义函数: • 用适当的数学实体表示每个短语的意义。 • 实体被称为短语的指称(denotation)。 • 通过将短语映射到其指称的函数,来规定程序设计语言的语义。 • 这些函数被称为语义函数(semantic functions)。 语义函数:短语→指称 语法与语义的关系: • 语义是依附于语法的; • 语义是独立于语法的,反映语言的真实含意; • 语法、语义是多对多的映射。 回顾属性文法: • 属性(如.type、.val等) • 语义规则
例1 语法与语义的关系 • 考虑二进制数,如"110"和"10101"。 • 数字"110"欲表示数值6, • 而数字"10101"欲表示数值21。 • 数字是一个语法实体,而数值是一个语义实体。数值是一个抽象概念,它不依赖于任何特别的语法表示。 • 数字"110":数值:6、110等 • 数值6: 数字:"110"、"6"、"Ⅵ"、"六"、"陆"等 • 数值110: 数字:"110"、"6E"、"壹佰壹拾"等
例2 二进制数的语法与语义 语法: 域: 语义函数: 语义方程: 计算: Numeral ::= 0 | 1 | N0 | N1 Natural = { 0, 1, 2, 3, ... } valuation : N → Natural valu[0]= 0 valu[1]= 1 valu[N0]= 2×valu N+0 = 2×valu N valu[N1]= 2×valu N+1 valu[110] = 2×valu[11] = 2×(2×valu[1]+1) = 2×(2×1+1) = 6 valu[110] = 10×valu[11] = 10×(10×valu[1]+1) = 10×(10×1+1) = 110 N::=i|Ni (i=0, 1, 2... base-1) base进制:valu[i]= i (i=0, 1, 2... base-1) valu[Ni]= base×valu[N]+i
例3 一个计算器的语法与语义 文法: 域: 语义函数: 辅助函数: 语义方程: • Command ::= Expr = (6.4) • E ::= Numeral (6.5a) • | E + E (6.5b) • | E - E (6.5c) • | E * E (6.5d) • int = { ..., -3, -2, -1, 0, 1, 2, 3, ... } • execute : Command → int (6.6) • evaluate : E → int (6.7) • valuation : Numeral → Natural (6.8) • sum : int×int→ int • diff : int×int→ int • prod : int×int→ int • exec[E=]= eval E (6.9) • eval[N]= valu N (6.10a) • eval[E1+E2]= sum(eval E1, eval E2) (6.10b) • eval[E1-E2]= diff(eval E1, eval E2) (6.10c) • eval[E1*E2]= prod(eval E1, eval E2) (6.10d)
例3 一个计算器的语法与语义(续) 语义方程: 计算: exec[E=]= eval E (6.9) eval[N]= valu N (6.10a) eval[E1+E2]= sum(eval E1, eval E2) (6.10b) eval[E1-E2]= diff (eval E1, eval E2) (6.10c) eval[E1*E2]= prod(eval E1, eval E2) (6.10d) 执行命令“40-3*9=” ,其中减法优先级高于乘法: exec[40-3*9=] = eval[40-3*9] by(6.9) = prod(eval[40-3],eval[9]) by(6.10c) = prod(diff(eval[40], eval[3]), eval[9]) by(6.10d) = prod(diff(valu[40], valu[3]), valu[9]) by(6.10a) = prod(diff(40,3), 9)= 333
定义1.1 • 每个短语p的意义被规定为一个在某域中的值d。称d是短语p的指称。或者说短语p由d来指称; • 规定域D作为短语类P的指称,并且引入一个语义函数f,它把P中的每个短语映射到它在D中的域。记为: • f : P → D; • 通过若干语义方程来定义语义函数,每个函数对应P中的一个可区分的短语。如果P中的一个短语有子短语Q和R,则相应的语义方程式就类似如下表示: • f[...Q ...R ...]= ... f' Q ... f'' R ... • 此处f'和f''分别是Q和R的语义函数。 ■ 换句话说,每个短语的指称(仅)由它们子短语的指称定义,从而使得整个程序的意义自下而上得以完整定义。
1.2 函数定义的符号表示 • 使用符号“let ... in ...”引入新的(数学意义的)变量或函数,其含意可以非形式地解释为:“将…引入…”或“将…代入…”。 • 例:let s=0.5*(a+b+c) in sqrt(s*(s-a)*(s-b)*(s-c)) • let succ n=n+1 in … succ m, … succ(succ i)) … • 其中的s是变量,而succ是函数。 • 使用函数的匿名表示忽略函数名而仅关注其实际意义。用匿名函数λn.n+1表示n→n+1,则下述均可表示为匿名函数: • succ = λn.n+1 • pred = λn.n-1 • odd = λn.true-value • 于是succ可以表示为:let succ = λn.n+1 in ...
3. 多个参数与let ... in ...结构的嵌套(或组合)。 1.2 函数定义的符号表示(续) • 例:let triangle-area(a,b,c) = • let s = 0.5*(a+b+c)in • if s>0.0 • then sqrt(s*(s-a)*(s-b)*(s-c)) • else 0.0 • in triangle-area(0.3, 0.4, 0.5) 函数triangle-area的域是real×real×real→real,可以将triangle-area看作一个三元组的单一参数,a,b,c分别是它的三个分量。
1.3 域(Domains) 域是一个值的集合,这些值被称为域的元素。指称语义中所使用的域结构有下述几种。 • <1> 原子域(Primitive domains) • 原子域是这样的域,它的元素是原子的值,而不是可以由更简单的值组合而来的值。原子域包括: • Character- 元素来自字符集合 • Integer- 元素是零、正整数、负整数 • Natural- 元素是非负整数 • Truth-Value- 元素是真值false和true • Unit- 唯一元素是零元组,记为:0-tuple() 也可以用枚举的方法来定义原子域,例如: Denomination = { dollars, cents } 或者:Denomination = { 元、角、分}等
<2> 迪卡尔积域(Cartesian product domains) 1.3 域(Domains)(续1) a.迪卡尔积域D1×D2×...×Dn的元素是有序n元组,(x1, x2, ..., xn),其中xi∈Di。当n=2时,域中元素是有序对。 例1Money=Natural×Denomination的元素可以取: (1,dollars)、(2,cents)等。 b.元组的构造与分解 用let x=(...) in ...构造元组; 用let (...)=x in ...分解元组。 例2构造一个money类型的元组: let pay = (payrate×hours,dollars) in ... 例3将money类型分解为两个分量的乘积: let (amount,denom) = pay in amount×(if denom=dollars then 100 else 1)
<3> 异或域(Disjoint union domains) 1.3 域(Domains)(续2) a.异或域D1+D2+...+Dn的元素选自分量的域:x∈Di(i=1,2...n)。 异或域的各分量域应被标记(命名),以明确取自的分量。 例1异或域Shape=rectangle(Real×Real)+circle Real+point的元素:rectangle(0.3,0.4)、cirle 5.0或point(point Unit) • b.异或域分解也用let ... in ...,但需多重函数分情况定义 • 例2let sheet = rectangle(lgth,lgth/sqrt 2.0) in -- sheet:Shape • ... • let area(rectangle(w,d)) = w*d -- area:Shape→Real • area(circle r) = pi*(r*r) • area(point) = 0.0 • in • ... • area(sheet) area由三个独立的公式定义
<4> 函数域(Function domains) 1.3 域(Domains)(续3) a.函数域的元素是函数或映射。每个函数域D→D'的元素是一个函数,它把D中的元素映射到D'中的元素。 例1域Integer→Truth-Value的元素,是把整型数映射到真值的函数,如odd,even,positive,negative,prime,composite等。 回顾:odd=λn.true-value b.域D→D'上的一个偏(partial)函数是这样一个函数,它可以仅成功地作用于D中的部分参数。经常用偏函数来规定语义。 例2若除法函数的参数对中的第二个数值是0,就不能成功地应用除法函数。 假设每个域都包括一个特殊的元素fail,它可以用来作为偏函数的结果。
<5> 序列域(Sequence domains) 1.3 域(Domains)(续4) a.序列域D*中的每个元素是从D中选出的零个或多个元素的有限序列。每个序列或者是空序列nil,或者是把序列s∈D*加上前缀x∈D而得到。 例1域String=Character*的元素是零个或若干个字符的序列,即任何长度的字符串。例如: nil -- 习惯上写为“” 'a'.nil -- 习惯上写为“a” 'S'. 'u'. 's'. 'y'.nil -- 习惯上写为“Susy” • b.使用由两个序列定义的函数来分解序列。 • 例2 • let length(nil) = 0 -- length : D*→Integer • length(x.s) = 1 + length s • in • ...
本节主要内容 1 指称语义的基本概念:短语 → 指称 2 语义函数与指称语义的基本过程 ① 语法(短语) ② 域(指称) ③ 语义函数(短语→指称) ④ 语义方程与辅助函数 3 函数定义的符号表示 ① 使用符号“let ... in ...”引入新的变量与函数; ② 匿名函数λn.n+1 ③ 多个参数与let…in…结构的嵌套 4 域 ① 原子域 ② 迪卡尔积域 ③ 异或域 ④ 函数域 ⑤ 序列域
参考书目 David A. Watt “Programming Language Syntax and Semantics”, Prentice Hall,1991 习题 • 分别用二进制和十进制的指称语义,确定: (a) valuation[11]; (b) valuation[0110]; (c) valuation[10101]。 • 为计算器增加一个求平方操作,在它的操作数之后键入“sq”键,如命令“7+2sq=”(它的结果是81)。修改相应的指称语义。 • (a)用head与tail定义串的组合与分解; (b)如何定义substring、prefix、postfix等?
存储模型与环境模型 西安电子科技大学 软件工程研究所刘 坚
上节内容回顾 • 指称语义的基本概念:将语言的意义施加于语言的结构 • 语义函数与指称语义的基本过程 ① 语法(短语) ② 域(指称) ③ 语义函数(短语→指称) ④ 语义方程与辅助函数 • 函数定义的符号表示 ① 使用符号“let ... in ...”引入新的变量与函数; ② 匿名函数λn.n+1 ③ 多个参数与let…in…结构的嵌套 • 域 ① 原子域 ② 迪卡尔积域 ③ 异或域 ④ 函数域 ⑤ 序列域
本节主要内容 一、存储(Storage) 1.1 存储模型 1.2 存储模型举例 二、环境(Environment) 2.1 环境模型 2.2 环境模型举例 • 掌握 • 如何用指称语义描述存储与环境的动态特性和建立动态模型; • 如何用存储模型和环境模型描述具体的存储与环境。
一、存储(Storage) 存储是计算机的重要基础概念之一 计算机模型:程序存储+程序执行 程序设计语言:内容可更改的变量x 数学模型:内容可更改的配置(location或cell) 第一类值(first-class values):可以参与语言所有操作而不受限制的值(如赋值、参数传递等),简称为值(Value)。
1.1 存储模型 定义1.2简单存储模型是若干配置(location)的集合,每个配置有一个状态: ① 未使用(unused),没有被分配给任何变量。 ② 未定义(undefined),已经被分配,但是没有值。 ③ 含有一个值(stored storable)。 可存储在配置中的值被称为可存储值(storable)。某一时刻存储的全体被称为存储瞬象(storage snapshots),用术语存贮(store)表示。 ■ 定义1.2可以用一个公式表示为: Store=Location→(stored Storable + undefined + unused) (6.16) 可以通过命令来改变存贮,如n:=13将sto映射到sto’。 二者的区别是sto’中含有了值13。
① 描述存储基本特性的辅助函数 • 称配置域为Location,可存储域为Storable,存贮域为Store。则存储特性可表示为下述映射: • empty-store : Store (6.11) • allocate : Store → Store×Location (6.12) • deallocate : Store×Location→Store (6.13) • update : Store×Location×Storable→Store (6.14) • fetch : Store×Location →Storable (6.15) • empty-store给出一个存贮,其中每一个配置都是未使用。 • allocate(sto)=(sto',loc):sto'与sto相同,但是配置loc在sto中是未使用,而在sto'中是未定义。 • deallocate(sto,loc)=sto'意思是:sto'与sto相同,但是配置loc在sto'中未使用。 • update(sto,loc,stble)=sto'意思是:sto'与sto相同,但是sto'中的配置loc含有stble。 • fetch(sto,loc)给出存放在sto中配置loc里的可存储值,如果loc未定义或者是未使用,给出值fail。
辅助函数的符号表示 empty-store =λloc.unused (6.17) • allocate sto = let loc=any-unused-location(sto) (6.18) • in (sto[loc→undefined],loc) • (sto[loc→state]= • λloc'.if loc'=loc then state else sto(loc') • 即loc被修改为state,其它保持状态不变 ) • 找到任何一个“未使用”的配置loc,将其置为“未定义” deallocate(sto,loc) = sto[loc→unused] (6.19) update(sto,loc,stble) = sto[loc→stored stble] (6.20) fetch(sto,loc) = (6.21) let stored-value(stored stble) = stble stored-value(undefined) = fail stored-value(unused) = fail in stored-value(sto(loc))
③举例 一个具有四个配置loc1,loc2,loc3,loc4(从左到右)的存贮,其中数字、‘?’和‘$’分别表示配置的值、未定义和未使用状态。 fetch(3?$$,loc1) = 3 fetch(3?$$,loc2) = fail fetch(3?$$,loc3) = fail update(3?$$,loc2,7) = 37$$ deallocate(3?$$,loc2) = 3$$$ allocate(3?$$) = (3??$,loc3) 或者(3?$?,loc4) 可以看出:deallocate(allocate sto) = sto fetch(update(sto,loc,stble),loc) = stble 例如: deallocate(allocate (3?$$)) = (3?$$) fetch(update(3?$$,loc2,7),loc2) = 7 但是: allocate(deallocate(sto, loc)) ≠ sto 因为可以:allocate(deallocate(3?$$,loc2)) ≠ 3?$$
文法:Command ::= E = (6.4) E ::= Numeral (6.5a) | E + E (6.5b) | E - E (6.5c) | E * E (6.5d) 域:int = { ..., -2, -1, 0, 1, 2, ... } 辅助函数: sum : int×int→ int diff : int×int→ int prod : int×int→ int 1.2 存储模型实例-无存储的计算器 语义函数:execute : Command → int (6.6) evaluate : E → int (6.7) valuation : Numeral → Natural (6.8) 语义方程: 计算: exec[E=]= eval E (6.9) eval[N]= valu N (6.10a) eval[E1+E2]= sum(eval E1, eval E2) (6.10b) eval[E1-E2]= diff(eval E1, eval E2) (6.10c) eval[E1*E2]= prod(eval E1, eval E2) (6.10d) exec[40-3*9=] = eval[40-3*9] by(6.9) = prod(eval[40-3],eval[9]) by(6.10d) = prod(diff(eval[40], eval[3]), eval[9]) by(6.10c) = prod(diff(valu[40], valu[3]), valu[9]) by(6.10a) = prod(diff(40,3), 9)= 333
将计算器扩充为具有存储功能,它包括两个寄存器(cells)x和y。将计算器扩充为具有存储功能,它包括两个寄存器(cells)x和y。 • 可以键入如下形式的命令序列: • “3*37=x” • “9+x=” • 第一条命令计算3和37的乘积,显示结果,并把结果存放在寄存器x中。 • 第二条命令计算9和x中内容的和,并显示结果。 1.2 存储模型实例-有存储的计算器 ① 文法 Command ::= Expression = (6.22a) | E = Register (6.22b) | C C (6.22c) E ::= Numeral (6.23a) | E + E (......) (6.23b) | R (6.23e) R ::= x (6.24a) | y (6.24b) Command ::= E = (6.4) E ::= Numeral (6.5a) | E + E (6.5b) | E - E (6.5c) | E * E (6.5d)
1.2 存储模型实例-有存储的计算器(续1) ② 域 Storable = Integer (6.25) Location = {loc1,loc2} (6.26) ③ 语义函数 a.命令的执行: execute : C → (Store → Store×Integer) (6.28) (命令的指称是一个把存贮映射到存贮和整型数的函数) b.表达式的计算: evaluate : E → (Store → Integer) (6.27) (表达式的指称是一个把存贮映射到整型数的函数(结果依赖于存贮)) c.寄存器的定位: location : R → Location (6.29) (寄存器的指称是一个配置)
③语义方程 1.2 存储模型实例-有存储的计算器(续2) a.寄存器的定位: loca[x]=loc1 (6.32a) loca[y]=loc2 (6.32b) • b.表达式的计算(E→(Store→Integer) ) • eval[N]sto = valu N (6.30a) • eval[E1+E2]sto = sum(eval E1sto,eval E2sto) (6.30b) • eval[R]sto = fetch(sto,loca R) (6.30e) • c.命令的执行 • exec[E=]sto = let int = eval E sto in (sto,int)(6.31a) • (在不变的存贮sto中计算E得到的值int) • exec[E=R]sto= • let int = eval E sto in (6.31b) • let sto' = update(sto,loca R,int) in (sto',int) • (给出改变了的存贮sto'和在sto中计算E得到的值int) • exec[C1C2]sto = (6.31c) • let(sto',int) = exec C1 sto in exec C2 sto' • (在存贮sto中执行C1,在改变了的存贮sto'中执行C2) 下一页 下下页
1.2 存储模型实例-有存储的计算器(续3) 用存储模型给出命令序列3*37=x 9+x=(C1 C2)的解。 解:首先在sto中执行命令3*37=x,得到一个值和一个改变了的sto',然后在sto'中执行命令9+x=,得到一个值且sto'保持不变。一开始,sto=(loc1,loc2)=(未使用,未使用) • exec[3*37=x]sto • = let int=eval[3*37]sto in • let sto'=update(sto,loca x,int)in(sto',int) (by 6.31b) • = let int=prod(eval[3]sto, eval[37]sto) • in let sto'=update(sto, loca x, int) in (sto', int) • = let int=111 in let sto'=update(sto,loca x,int)in(sto',int) • = let sto'=update(sto,loca x,111) in (sto', 111) • = let sto'=update(sto, loc1, 111) in (sto', 111) (by 6.32a) • = ((111,未使用), 111) (by 6.20) 即执行3*37=x之后,sto'=(111,未使用),x获得值111且屏幕显示值111。
1.2 存储模型实例-有存储的计算器(续4) 然后在sto'=(111,未使用)中执行9+x=: • exec[9+x=]sto' • = let int=eval[9+x]sto' in (sto', int) (by 6.31a) • = let int=sum(eval[9]sto', eval[x]sto') in (sto', int) • = let int=sum(9,fetch(sto',loca x))in(sto', int) (by 6.30e) • = let int=sum(9,fetch(sto',loc1))in(sto', int) (by 6.32a) • = let int=sum(9,111) in (sto', int) (by 6.32a) (by 6.21) • = let int=120 in (sto', int) • = (sto', 120) • = ((111,未使用), 120) 最终结果是x中获得值111,屏幕显示值120。■
二、环境(Environment) 声明建立标识符和某种实体之间的绑定(bindings)。每个绑定具有一个确定的作用域(scope),如含有建立绑定的声明的块(block)。 通俗地讲,环境是在一定的作用域范围内的一组绑定。可以表示为:{A→B, ...}。 例1开发环境:{Computer→PC,OS→Unix,PL→C++,DBMS→Oracle} 例2按语法let D in E书写的表达式如下: ① let val m=10 in ② let val n=m*m in m+n 假设在空环境{ }中计算表达式① ,第一个声明建立绑定m→10,它的作用域是表达式②。 然后在环境{m→10}中计算②的子表达式"m*m",得到结果100,因为m的每个应用出现都指称10。 第二个声明建立绑定n→100,它的作用域是表达式"m+n"。于是m+n在环境{m→10,n→100}中计算并得到110。
例3作用域的嵌套: 二、环境(Environment)(续) ③ let val n=1 in ④ n+(let val n=2 in 7*n)+n 同样,空环境中计算表达式③,建立环境{n→1},在此环境中计算表达式④, ④中有一个被嵌套的子表达式let val n=2 in 7*n,其中声明将环境改变为{n→2}。因此7*n=7*2=14,而: n+(let val n=2 in 7*n)+n=1+14+1=16 ■ 定义3.3环境是一组与作用域有关的标识符到实体的绑定。标识符在一个作用域中最多有一个绑定,被绑定的实体称为可绑定体。■ 定义3.3可表示为公式: Environ=Identifier→(bound Bindable + unbound) (6.37) 可绑定体的简化:通常需要经过两步才能将名字映射到它所代表的值,此处简化为一步,并且仅有integer是可绑定体。
2.1 环境模型① 描述环境基本特性的辅助函数 若令环境域为Environ,标识符域为Identifier,可绑定体域为Bindable,则环境特性可表示为下述映射: empty-environ : Environ (6.33) bind : Identifier×Bindable → Environ (6.34) overlay : Environ×Environ → Environ (6.35) find : Environ×Identifier → Bindable (6.36) • empty-environ给出一个空环境{}。 • bind(Id,bdble)给出由单一绑定组成的环境{Id→bdble}。 • overlay(env’,env)给出一个组合环境env和env’绑定的环境;若任何标识符既被env也被env’绑定,则它在env’的绑定重置在env的绑定。 • find(env,Id)给出环境env中Id的可绑定体,若无就给出fail。 例如:设env = {i→1,j→2}, 则: bind(k,3) = {k→3} overlay({j→3,k→4},env) = {i→1,j→3,k→4} find(env,j) = 2,而find(env,k) = fail
②辅助函数符号表示 empty-environ =λId.unbound (6.38) bind(Id,bdble) = (6.39) λId'.if Id'=Id then bound bdble else unboud overlay(env',env) = (6.40) λId.if env'(Id)≠unbound then env'(Id) else env(Id) find(env,Id) = (6.41) let bound-value(bound bdble) = bdble bound-value(unbound) = fail in bound-value(env(Id)) 与存储模型对应:empty-store、allocate、update、fetch。 问题:deallocate?
2.2 环境模型实例-含有声明的语言 ①文法 E ::= N (6.42a) | E + E (6.42b) | ... | Id (6.42c) | let Declaration in E (6.42d) D ::= val Id = E (6.43) ② 域:Bindable = Integer (6.44) ③ 语义函数: evaluate : E → (Environ → Integer) (6.45) (表达式的指称是一个从环境到整型数的映射;) elaborate : D → (Environ → Environ) (6.46) (声明的指称是一个环境到环境的映射。)
2.2 环境模型实例-含有声明的语言(续1) ④ 语义方程 eval[N]env = valu N (6.47a) eval[E1+E2]env = sum(eval E1 env,eval E2 env) (6.47b) eval[Id]env = find(env,Id) (6.47c) eval[let D in E]env = (6.47d) let env'=elab D env in eval E(overlay(env',env)) elab[val Id=E]env = bind(Id,eval E env) (6.48) • 计算env中数字N组成的表达式的结果就是N的值; • 计算env中表达式"E1+E2"的结果,是在各自env中计算E1和E2结果的和; • 计算env中引用标识符Id的结果是Id绑定到env的值; • 计算在env中形如"let D in E"表达式的结果,是计算E在一个新环境中的结果。新环境是由在env中详细描述D产生的绑定env'所覆盖得到的; • 详细描述在env中形如"val Id = E"声明的结果,是一个从Id到由计算env中E得到的值的绑定。
2.2 环境模型实例-含有声明的语言(续2) ⑤例:空环境env中计算:let val n=1 in n+(let val n=2 in 7*n)+n 解: eval[let val n=1 in n+(let val n=2 in 7*n)+n]env = let env'=elab[val n=1]env (by 6.47d) in eval[n+(let val n=2 in 7*n)+n]overlay(env', env) = let env'=bind(n,eval[1]env) (by 6.48) in eval[n+(let val n=2 in 7*n)+n]overlay(env', env) = let env'= bind(n, 1) in eval[n+(let val n=2 in 7*n)+n]overlay(env', env) = let env'={n→1} (by 6.39) in eval[n+(let val n=2 in 7*n)+n]overlay(env', env) = eval[n+(let val n=2 in 7*n)+n]env' (因为env={ }, 所以overlay(env', env)=env'={n→1})
2.2 环境模型实例-含有声明的语言(续3) = sum(eval[n+(let val n=2 in 7*n)]env', eval[n]env') = sum(sum(eval[n]env',eval[let val n=2 in 7*n]env'), eval[n]env') = sum(sum(find(n, env'), let env''= elab[val n=2]env' in eval[7*n]overlay(env'',env'),find(n,env')) (by 6.47c,6.47d) = sum(sum(1, let env''= bind(n, eval[2]env') (by 6.48) in eval[7*n]overlay(env'', env'),1) = sum(sum(1, let env''=bind(n, 2) eval[7*n]overlay(env'', env'),1) = sum(sum(1, let env''={n→2} eval[7*n]overlay(env'', env'),1) = sum(sum(1, eval[7*n]overlay(env'', env'),1) = sum(sum(1, eval[7*n]env'', 1) (overlay(env'', env')={n→2}=env'') = sum(sum(1, prod(eval[7]env'', eval[n]env'')), 1) = ... = sum(sum(1, 14), 1) = sum(15, 1) = 16 ■
内容回顾 • 存储模型 • Store=Location→(stored Storable + undefined + unused) (6.16) 辅助函数的符号表示: empty-store =λloc.unused (6.17) allocate sto = let loc=any-unused-location(sto) (6.18) in (sto[loc→undefined],loc) deallocate(sto,loc) = sto[loc→unused] (6.19) update(sto,loc,stble) = sto[loc→stored stble] (6.20) fetch(sto,loc) = (6.21) let stored-value(stored stble) = stble stored-value(undefined) = fail stored-value(unused) = fail in stored-value(sto(loc)) • 举例-带存储的计算器: • 文法的修改; • 域、语义函数、语义方程的设计
内容回顾(续) • 环境模型 • Environ=Identifier→(bound Bindable + unbound) (6.37) • 辅助函数的符号表示: empty-environ =λId.unbound (6.38) bind(Id,bdble) = (6.39) λId'.if Id'=Id then bound bdble else unboud overlay(env',env) = (6.40) λId.if env'(Id)≠unbound then env'(Id) else env(Id) find(env,Id) = (6.41) let bound-value(bound bdble) = bdble bound-value(unbound) = fail in bound-value(env(Id)) 环境强调作用域,离开作用域,绑定自然消失,故没有去绑定 • 举例-含有声明的语言: • 文法的修改; • 域、语义函数、语义方程的设计
习题 1. 用带寄存器的计算器的指称语义(假设寄存器初值均为0): (a)执行命令“x+7=”; (b)执行命令“x+7=y y*y=”。 2*. 拓广计算器使得它有一个大存贮的寄存器,R0,R1,R2等(x和y键由单一的R键所代替)。 3. 使用带声明表达式的指称语义: (a) 计算环境{ m→10,n→15 }中的表达式“m+n”; (b) 计算空环境中的表达式 “let val n=1 in n+(let val n=2 in 7*n)+n”。
本节主要内容 • 抽象 • 函数抽象 • 过程抽象 • 参数 • 组合类型 • 失败 • 了解 • 抽象的种类,抽象的数学模型; • 参数的种类,参数的数学模型; • 组合类型的构造,组合类型的存取; • 失败的数学模型,失败的传播。
一、抽象(Abstractions) 抽象是一个体现了计算的值(如函数抽象或过程抽象)。用户称计算为抽象,因为他们只能“看到”计算的结果(如有函数抽象所产生的值,或由过程的作用所改变的存储等),而不是计算结果的方法。 我们首先分别考察函数和过程抽象的语义。为简单起见,假设每个抽象具有单一(常量)参数。 然后再详细地考察参数。
1.1 函数抽象(Function abstractions)(不改变存储的抽象) • 函数抽象的使用者提供一个实参,并且只能“看到”结果值。因此函数抽象的意义应该是从实参到结果值的映射。 • 更一般地,在规定的语言中,令Argument是实参域,Value是第一类值域。则有: • Function = Argument→Value (6.62) • <1> 语法 • 扩展语法,加入函数调用(6.63)和函数声明(6.64): • Expression ::= ... • | Identifier ( Actual-Parameter) (6.63) • Declaration ::= ... • | fun Id ( Formal-Parameter ) = E (6.64) • FP ::= Id : Type-denoter (6.65) • AP ::= E (6.66)
1.1 函数抽象(续1) <2> 指称 假设有上下文限制:标识符必须已被声明为一个函数,并且实参必须与对应形参具有相同类型。 在算术表达式中,只有整型数可以作为参数传递,并且只有整型数可以作为函数结果返回: Argument = Integer (6.67) Function = Argument → Integer (6.68) 值声明绑定一个标识符到一个整型数,而函数声明绑定一个标识符到一个函数抽象。因此整型数和函数抽象均是可绑定体: Bindable = integer Integer + function Function (6.69) 标记 域
1.1 函数抽象(续2) • <3> 语义函数 • evaluate : E → (Environ →Integer) (3.45) • elaborate : Dec → (Environ→Environ) (3.46) • bind-parameter: FP → (Argument→Environ) (6.70) • give-argument: AP → (Environ→Argument) (6.71) • 函数调用的指称和实参的指称,均象表达式一样,是一个环境到整型数的映射; • 函数的声明是一个绑定的集合,即环境到环境的映射; • 形参的指称是一个从实参到环境的函数。