版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第11章 函数式程序设计语言过程式程序设计语言由于数据的名值分离, 变量的时空特性导致程序难于查错、难于修改命令式语言天生带来的三个问题只解决了一半滥用goto已经完全解决悬挂指针没有完全解决函数副作用不可能消除问题是程序状态的易变性(Mutability)和顺序性(Sequencing)Backus在图灵奖的一篇演说程序设计能从冯诺依曼风格下解放出来吗?中极力鼓吹发展与数学连系更密切的函数式程序设计语言11.1 过程式语言存在的问题(1)易变性难于数学模型代数中的变量是未知的确定值,而程序设计语言的变量是对存储的抽象根本解决: 能不能不要程序意义的“变量”只保留数学意义的“变量”?能不能消除
2、函数的副作用?例:有副作用的函数 int sf_fun(int x) static int z = 0; /第一次装入赋初值 return x + (z+); sf_fun(3) = 3 |4 | 5 | 6 | 7 /随调用次数而异,不是数学意义的确定函数。(2)顺序性更难数学模型顺序性影响计算结果, 例如, 前述急求值、正规求值、懒求值同一表达式就会有不同的结果。有副作用更甚, 因而难于为程序建立统一的符号数学理论。应寻求与求值顺序无关的表达方式理想的改变途径没有变量, 就没有破坏性赋值, 也不会有引起副作用的全局量和局部量之分。 调用通过引用就没有意义。 循环也没有意义, 因为只有每次执
3、行循环改变了控制变量的值, 循环才能得到不同的结果。那么程序结构只剩下表达式、条件表达式、递归表达式。演算演算是符号的逻辑演算系统, 它正好只有这三种机制, 它就成为函数式程序设计语言的模型演算是一个符号、逻辑系统,其公式就是符号串并按逻辑规则操纵Church的理论证明, 演算是个完备的系统, 可以表示任何计算函数, 所以任何可用演算仿真实现的语言也是完备的。演算使函数概念形式化,是涉及变量、函数、函数组合规则的演算。演算基于最简单的定义函数的思想: 一为函数抽象x.E, 一为函数应用(x.E)(a)。一切变量、标识符、表达式都是函数或(复合)高阶函数。如x.C(C为常量)是常函数。11.2.
4、1 术语和表示法(1)演算有两类符号: 小写单字符用以命名参数, 也叫变量。外加四个符号: ( 、) 、。、。大写单字符、 特殊字符(如+、-、*、/)、大小写组成的标识符代替一个表达式。(2)公式 变量是公式,如y。如y是变量F是公式, 则y.F也是公式。如F和G都是公式, 则(FG)也是公式。(3)表达式 形如y.F为函数表达式, 以关键字开始, 变量y为参数。形如(FG)为应用表达式为了清晰,表达式可以任加成对括号。演算公式举例x 变量、公式、表达式。(x.(y)x) 函数, 体内嵌入应用。(z.(y(z.x) 函数, 体内嵌入应用, 再次嵌入函数。 (z.(z y)x) 应用表达式。x
5、.y.z.(x x.(u v)w) 复杂表达式(4) 简略表示 缩写与变形表达 下例各表达均等效: a.b.c.z.E = abcz.E = (abcz).E = (a,b,c,z).E =a.(b.(c.(z.E) 命名:以大写单字符或标识符命名其表达式 G = (x.(y(yx) (x.(y(yx)(x.(y(yx) = (G G) = H由于演算中一切语义概念均用表达式表达。 为了清晰采用命名替换使之更易读。T = x.y.x /逻辑真值F = x.y.y /逻辑假值1 = x.y.x y /数12 = x.y.x(x y) /数2zerop = n.n(x.F)T /判零函数注:zer
6、op中的F、T可以用表达式展开(5) 形式语法核心的演算没有类型, 没有顺序控制等概念, 程序和数据没有区分。 语法极简单: : = | . | () | () : =11.2.2 约束变量和自由变量 (x.(b x) x) 自由变量 约束变量(x.y.(a x y)(b (y.(x y)表达式中的作用域复盖(x.(x.(x a)(x b)(x c))PMNROQ第1个x约束于P第2个x约束于O第3个x在M中自由,约束于O,P第4个x在N中自由,约束于P第5个x在R中自由,在Q中这5个x均约束出现, b,c自由出现。11.2.3 基本函数TRUE 和FALSE的表达式 T = x.y.x F
7、= x.y.y整数的表达式: 0=x.y.y 1=x.y.x y 2=x.y.x(x y) n=x.y.x(x(x y) n个基本操作函数 not=z.(zF)T)=z.(zx.y.y)(x.y.x) and=a.b.(ab)F) = a.b.(ab)x.y.y) or = a.b.(aT)b) = a.b.(a x.y.x)b)以下是算术操作函数举例: + = add = x.y.a.b.(xa)(ya)b) * = multiply = x.y.a.(x(ya) * = sqr = x.y.(yx) identity = x.x /同一函数 succ = n.(x.y.nx(x y) /后
8、继函数zerop = n.n(x.F)T =n.n(z.x.y.y)(x.y.y) /判零 函数 例:3+4就写add 3 4, add 3返回“加3函数”应用到4上当然就是7。写全了是:(x.y.a.b.(x a)(y a) b )) (p.q.(p(p(p q)(s.t.(s(s(s(s t) a.b.(a(a(a(a(a(a(a b)11.2.4 归约与范式归约将复杂的表达式化成简单形式, 即按一定的规则对符号表达式进行置换。例:归约数1的后继 (succ 1) = (n.(x.y.n x(x y)1) = (x.y.1 x(x y) = (x.y.(p.q. p q) x(x y) =
9、 (x.y.(q. x q)(x y) = (x.y.x(x y)=2注:succ和1都是函数(1是常函数),第一步是n束定的n被1置换。 展开后, x置换p, (xy)置换q, 最后一行不能再置换了, 它就是范式, 语义为2。(1)归约:归约的表达式是一个应用表达式(x.M N), 其左边子表达式是函数表达式,右边是任意表达式。归约以右边的表达式置换函数体M中指明的那个形参变量。形式地,我们用N/X,M表示对(x.M N)的置换(规则略)。 关键的问题是注意函数体中要置换的变量是否自由出现,如:(x.x(x.(xy)(zz)=(zz)(x.(zz)y) /错误,第二x个非自由出现。=(zz)
10、(x.(xy) /正确例11-5 高层表示的归约 (n.add n n) 3 = add 3 3 /3置换n后取消n = 6 (f.x.f(f x) succ 7 = x.succ (succ x) 7 = succ (succ 7) = succ (8) = 9注:add,3, succ, 7, 9是为了清晰没进 一步展开为表达式。 但归约有时并不能简化, 如:(x.xx)(x.xx),归约后仍是原公式, 这种表达式称为不可归约的。 对应为程序设计语言中的无限递归。(2)归约是消除一层约束的归约:x.Fx = F (3)换名:归约中如发生改变束定性质, 则允许换名(后跟的变量名), 以保证原
11、有束定关系。 例如: (x. (y.x) (z y) /(zy)中y是自由变量 = y.(zy) /此时(zy)中y被束定了, 错误! = (x.(w.x)(zy) /因(y.x)中函数体 无y, 可换名 = w.(zy) / 正确!(4)归约约定顺序:每次归约只要找到可归约的子公式即可归约, 演算没有规定顺序。范式:符号归约当施行(除规则外)所有变换规则后没有新形式出现,则这种表达式叫范式。解释:范式即演算的语义解释, 形如 x x,(y (x.z)就只能解释为数据了。上述基本函数均为范式, 在它的上面取上有意义的名字可以构成上一层的函数, 如:pred =n.(subtract n 1)(
12、5) 综合规约例题:以演算规约3*2 3*2=*(3)(2) =x.y.(y x)(3)(2) (y.(y 3)(2) (2)3) = (f.c.f ( f c ) ) (3) c.( 3 ( 3 c ) ) = c.(f.c.(f(f(f(c)(3 c) / 有c不能置换c c.(f.z.(f (f (f (z)(3 c) c.(z.(3 c)(3 c)(3 c)(z) / 再展3=c.z.( f.c.(f(f(f(c)c)(3c)(3c)(z)c.z.( f.w.(f( f( f(w)c)(3c)(3c)(z)c.z.(w.(c(c(c(w)(3c)(3c)(z)/同理展开第二个c,第三个
13、c=c.z.(w.(c(c(c(w)( p.(c(c(c(p)( q.(c(c(c(q)(z)c.z.(w.(c(c(c(w)( p.(c(c(c(p)(c(c(c(z)c.z.(w.(c(c(c(w)( (c(c(c(c(c(c(z) c.z.(c(c(c(c(c(c(c(c(c(z)= 911.2.5 Church-Rosser定理按照演算的运算规则,谁先归约最后归约出的结果是一样的。例: 不同归约次序的正规演算得同一结果(x.(x y)(u.(u v)(p.(p q) r)(u.(u v) y)(p.(p q) r) ((x.(x y)(u.(u v)(r q)(y v)(p.(p q)
14、 r) (u.(u v) y)(r q) (u.(u v) y)(r q)(y u)(r q) (y u)(r q) (y u)(r q)(1) 严格函数 归约直到不可归约时正常终止, 除开不可归约函数而外, 有些函数尽管在符号上可归约, 语义上无任何意义, 到机器上不可执行的。 这就是所谓停机问题, 一般说来, 停机问题是不可判定的, 但我们在表示上给它以符号, 例如:divide m 0 = 表示该函数非正常终止, 是一个不代表任何值的值。不终止的计算结果值为 若f = 则称f为严格函数 若f =v ,v为确定的值,则f为非严格函数 正是由于有非严格函数的存在, 就产生了求值次序的问题非严
15、格函数取决于次序的例子例:演算不同求值次序的归约(n. multiply n n ) add 3 4 ) /先做右端子表达式 = (n. muliply n n) 7 /急求值= multiply 7 7 = 49= mutiply (add 3 4 )(add 3 4 ) /先做归约= mutiply 7 (add 3 4 )= mutiply 7 7 = 49 /正规求值若为 mutiply (add 3 4 )(add 3 4 ) /两个表达式一样,后一个不归约,取前一个的值。 = mutiply 7 7 = 49 /懒求值重述Church-Rosser定理 如按正规求值次序对某表达式E
16、求值结果为正常值v, 则按其他求值次序可能是v也可能是 。若按正规求值结果为 即非正常终止, 则按任何求值规则结果也为 正规求值是由外向里 Outside_in求值急求值是由里向外 Inside_out求值11.2.6 增强演算只用最底层演算是极其复杂的。用高层命名函数,语义清晰。不仅如此,保留一些常见关键字,语义更清晰。例如,我们可以定义一个if_then_else为名的函数:if_then_else =p.m.n.p m n,当p为真时, 执行m否则为n。我们先验证其真伪。例:当条件表达式为真时if_then_else函数的归约(if_then_else) T M N= (p. m. n.
17、 p m n) T M N = (m.n. ( T m n)M N= (m. n. (x.y.x) m n) M N= (m. n. (y.m) n) M N = (m. n. m) M N= (n. M) N=Mif表达式 可保留显式if-then-else形式: (if_then_else) E1 E2 E3= if E1 then E2 else E3 其中E1, E2, E3为表达式。 Let/where表达式 如果有高阶函数: (n. multiply n (succ n) (add i 2 ) = multiply (add i 2) (succ (add i 2) /n 和 ad
18、d i 2置换变元得 = multiply n (succ n) / let n = add i 2 in let a = b in E (a. E) b E where a=b (f. E2) (x.E1) = let f = x.E1 in E2 = let f x = E1 in E2其中形如f=x.E1的x. 可移向左边为f x = E1 。 如: sqr = n. multiply n n /整个是函数表达式 sqr n = multiply n n /两应用表达式也相等 let表达式在ML. LISP中直接采用, Miranda用where关键字使程序更好读, let直到E完结构成
19、一个程序块。Miranda只不过把where块放在E之后. 元组表达式一般情况下n元组是p=(x1,x2,xn), 建立在p上函数有:let f(x1,x2,xn)=E1 in E2 let fp=E1 in let x1=first p in let x2=second p in . . . let xn=n_th p in E211.3 函数式语言怎样克服命令式语言的缺点11.3.1 消除赋值赋值语句在过程语言中起什么作用。 在函数式语言中取消会有什么问题: 1 存储计算子表达式的中间结果。 2 条件语句的重要组成。 3 用于循环控制变量。 4 处理复杂数据结构(增删改某个成分)。Mira
20、nda解决办法 1:保留全局量、局部量(符号名)以及参数名。2:用条件表达式代替条件语句,其返回值通过 参数束定或where子句束定于名字3:函数式语言都要定义表数据结构, 因为归约 和递归计算在表上很方便。 对整个表操作实 则是隐式迭代。 不用循环控制变量。 对于 顺序值也都用表写个映射函数即可隐式迭代。 部分达到作用3, 其它显式循环要用递归。4:禁止赋值意味着数据结构一旦创建不得修改,故采用如下函数式语言结构数据修改方式ABCEHGDFBCAFJI11.3.2 以递归代替while_do 组织仿真的要点是把递归函数体写入条件表达式。 循环终止条件是条件测试部分, 函数如有返回值放在the
21、n部分, 递归函数体放在else部分, 如果不需返回值则取消一部分(else)。11.3.3 消除顺序一旦语义相关无法传递数据, 非得写成嵌套函数不可(返回值自动束定到外套函数的变元上)例:pascal实现: c:=a+b; s:=sin(c * c); 。 write(a,b, c, s); /上面计算不进行是无法打印 /的逻辑上要有顺序。LISP 实现: (print (let (c(+ a b) let (s (sin (* c c) list a b c s ) /仍有顺序但在一个 /表达式内。自左至右处理即隐式顺序。Miranda实现: Answere a b = (a b c s
22、) where s= sin (c* c) c= a+b /多么清晰, 全然没有顺序11.3.4用嵌套代替语义相关的顺序 用懒求值代替顺序 利用卫式进一步消除顺序性Miranda的卫式表达式 gcd a b= gcd (a-b) b, ab = gcd a (b-a), a max2 2 = max2, max2 max1 3 = max1, otherwise where max1 = (max_tree n1) 4 max2 = (max_tree n2) 5如有应用: (max_tree leaf1) /结果值为3, leaf1用上例(max_tree tree1)/结果值为49,tre
23、e1用上例 表(list)Miranda表的表示法 /空表1.n /1到n,域表示odd_number = 1,3,.100 /1到100内奇数表,头两项及最后项必写eleven_up = 11. /10以上, 无限表表示evens = 10,12.100 /10以上偶数表至100,头两项及最后项必写evens_up = 12,14. /10以上偶数无限表, week _days = “Mon”,“Tue”,“Wed”,“Thur”,“Fri” /五个串值的表11.4.2 内定义操作Miranda定义了常规的算术运算符(+、-、*、/、div、mod)并按中缀表示使用。故内定义了一些有用的表操
24、作: L1 + L2 / 表L2并接到表L1的末尾 item:List / 将项item加到表List的头前 List ! n / 从表List中选取第n项 L1 - L2 / 从表L1中剔出L2的值 #List /返回表List的项(基)数11.4.3 定义函数Miranda把函数定义叫方程(equation)。例: 斐波那契数的函数定义, 用卫式表达式实现递归Fibonacci n = 1, n=0 = 1, n=1 = Fibonacci (n-1)+Fibonacci (n-2) n1 卫式表达式的值集应复盖所有的可能, 否则用otherwise。例: 利用where解二次方程quad
25、root a b c = error “complex roots”,delta 0 where delta = b*b - 4*a*c radix = sqrt delta term1 = -b/(2*a) term2 = radix /(2*a)Miranda完全按演算模型,每个函数都是一元运算,当有多个变元时, 函数名也是第一类对象, 它逐一应用到各个参数, 中间返回函数可以任意取名, 这种中间函数称Curry函数。例: 直角三角形求斜边长函数 hypotenuse a b = sqrt (a * a + b * b)调用时 hypotenuse 3 4 /=5也可写作: (hypote
26、nuse 3 ) 4 f 4 Miranda则写作为: f 4 where f = hypotenuse 3 /f=sqrt(9 + b*b)即 Curry 函数。例: Miranda用变阶函数实现类型参数化。type row_type=array0.9 of Integer;function Reduce(functionf(x:Integer,y:Integer):Integer; ar:row_type):Integer;/函数f是参数化的。var sum,k:Integer;begin sum:=ar0; for k=1 to 9 do sum:=f(sum,ark); reduce:
27、=sumend;function MyOp(s:Integer,y:Integer):Integer; /此处定义一实例函数。begin MyOp:=abs(x)+abs(y)end;function MySum(ar:row_type):Integer;begin MySum:=Reduce(MyOp,ar) end;上程序仅将 Reduce函数操作参数化。数组元素类型、长度还是固定的。Miranda都可以,它设3个参数:操作、表、单位元。单位元的值可用于归约过程的初始化值,也是空表时的返回值:reduce f n = n 1reduce f(a : x) n = f a (reduce x n) 2为了理解上不引起岐意,写明reduce的类型:reduce:(numnumnum) /第一变元f是函数类型(有 括号),它是二元算子 num /返回值是表,表元素是num类型 num /若空表映射为数,类型是num. num /最后映射返回值是num类型。2行中(a:x)是表头a和表尾x,右边函数体是表尾归约后与表头归约。1行指明空表规约 n 次是单位元的 n 次复合。11.4.4 表闭包表闭包是一个任意复杂结构的(无限)表。其语法是: :=| :=;| := := := 表闭包示例:ZF
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年监理工程师之水利工程目标控制通关试卷及完整答案详解(历年真题)
- 2026广东广州市花都区教育局区内招聘公办学校事业编制教师50人考试备考试题及答案解析
- 2026上海大学科研助理(派遣制)招聘38人考试备考题库及答案解析
- 聊城东昌府区古楼风景区招聘考试备考题库及答案解析
- 2026四川自贡城投集团招聘5人考试备考试题及答案解析
- 2026贵州黔西南州崇文高级中学春季学期招聘10人考试备考试题及答案解析
- 2026四川成都彭州市国经人力资源管理有限公司招聘考试备考题库及答案解析
- 2026浙江海正药业股份有限公司招聘考试参考题库及答案解析
- 2026年湖南长沙马坡岭街道社区卫生服务中心招聘考试参考题库及答案解析
- 2026年山东城市服务职业学院公开招聘人员(46名)考试参考试题及答案解析
- 禁止纹身主题班会课件
- 辽宁医药职业题库及答案
- 上市公司报销管理制度
- CJ/T 511-2017铸铁检查井盖
- 2025年党建工作知识竞赛测试题库及答案(完整版)
- GB/T 15268-2024桑蚕鲜茧
- 中国婴幼儿 科学配餐与食品制作指导手册
- 2024年广西机场管理集团限责任公司招聘156人高频500题难、易错点模拟试题附带答案详解
- 2024年湖南省永州市中考物理试卷(-含解析)
- 首届不动产登记技能大赛试题库-3地籍调查
- 旅游投诉处理课件
评论
0/150
提交评论