Scheme 4 Javaer-2.功能抽象

《编程导论(Java)?第3章功能抽象》按照功能抽象的逻辑发展,介绍在Java语言环境中的三种流程、子程序和结构化分解、接口与实现相分离以及抽象方法——功能抽象的最高形式。而把操作/表达式是Java编程中最原始和起步级别的功能抽象。

SICP中,作为函数式编程语言的Scheme,它以表达式为基本单元,其功能抽象/函数抽象更为直接:按照丘奇的λ演算,完成对函数抽象的基本描述:

W是参数为变量x的λ表达式,则λx . W是λ表达式,如λx.( x+1)。这种表达式λx . W给出了一个函数的定义:W是函数体,参数就是变量x。

现在回顾《SICP?第一章构造过程抽象》。

三个机制

Every powerful language has three mechanisms for accomplishing (organize our ideas about processes):

·        Primitive expressions。基本表达式是语言设计者关心的要素,程序员只是被动地知道它们。如原子/基本类型、特殊块(特殊形式)define、if,前缀表达式,基本操作符等。

·        means of combination。表达式定义中,组合表达式是基本要求。函数的组合则是函数式编程语言最典型的特征。数据类型的合成,也是编程语言的一个较重要的部分,只不过程序员自定义类型在C、Java中不那么引人注目

·       means of abstraction, 抽象的方式——给组合实体一个名字并作为操作的单元。这里,我们可以给常量、组合表达式、函数命名。值得注意的是,数据和函数之间的界限,在Scheme中被模糊。

表达式求值

复合表达式递归地还原到基本表达式的求值。

l        数的值就是它们自己。如同Java中的文字。

l        内置操作符的值,是完成相应操作的及其指令序列。

l        其他名字的值,是环境中关联到该名字的对象。

l        每一种特殊块(特殊形式)都有其自己的求值规则。

换言之,任何东西都是有其值,函数式编程语言特别关心值的稳定性——避免副作用。

环境(全局环境),保存/确定名字和值的关联,或者说它用于确定表达式中各种符号的含义。

函数应用的代换模型

有了f(x)=x+1,自然需要计算f(2),即给函数一个(实际)参数进行求值。按照丘奇的λ演算,函数应用:A、B是λ表达式,则 (A B) 也是λ表达式,表示将实参B带入函数A中。

虽然1.1.5介绍了“帮助我们领会函数执行过程的代换,但不是解释器实际的工作方式”。替换模型,不仅涉及解释器的工作细节,也说明“变化的数据”会导致什么问题。

(A B)表示将实参B带入函数A中,那么如何带入呢?

一种是将B求值后带入A,即‘‘evaluate the arguments and then apply‘‘,称为应用顺序求值(applicative-orderevaluation);

一种是将B带入A(有点像内联函数的方式),‘‘fullyexpand and then reduce‘‘,称为normal-order evaluation(不知道为什么翻译成“正则序求值”而不是正交)。

练习1.1 – 1.5

过程作为黑箱抽象

《编程导论(Java)?3.1.2 方法》讨论了功能分解或结构化分解(structured decomposition),《?3.1.3 接口与实现分离》介绍了Parnas原则。可能我写的更清楚或啰嗦?

形参必须是局部于方法体,嗯,平时没有注意其意义——是函数作为黑箱的前提。

约束变量=局部变量,不被约束的变量,自由变量或全局变量;

Scheme没有其他手段隐藏函数——如private,于是,在函数的内部定义函数——子函数局部化。

一个函数的内部,构成一个词法作用域。因此,其多个内部函数原来需要的形参x,可以作为词法作用域中的自由变量——类似Java中的成员变量的含义,而这些形参x被简化掉。

过程与执行流程

这个问题有意思。在C的教学中,有些人画流程图作为编写代码的“前期”工作。这一节,SICP说明“能够看清楚函数产生的后果的能力,对于成为程序设计专家是至关重要的”。

什么意思呢?我虽然不喜欢也不推荐学生画流程图,但是通过伪代码或源代码,我们能够知道过程/函数的执行流程,甚至我认为:能够看清楚函数产生的后果的能力,是一个基本能力。

但是,如果你解释器或编译器进行了优化,我需要知道函数的执行流程吗?如果需要,这就不是了解执行流程的问题,而是“深入Java虚拟机”的问题。

而在Scheme中,这一点(知道函数的执行流程)比较重要:因为递归。

如果你对递归不熟悉,其实,那么任何语言中,你都需要学习它的执行流程;如果你对递归比较熟悉,那么你需要知道Scheme中强调这一点的目的:因为想把递归变成循环以提高效率——尾递归。

除了递归之外,“知道函数的执行流程”是显而易见的。

以阶乘为例。

递归代码如下。

(define (factorial n)

(if (= n 1)

1

(* n(factorial (- n 1)))))

其执行流程, SICP中给出了一个图。

但是其解释,我认为欠考虑。“Thesubstitution model reveals a shape of expansion followed by contraction,indicated by the arrow in figure x”,“递归计算过程”本质上就是“轻率地”认为自己的较简单的情形是已知的,因而通过“展开和收缩”方式计算,在Java中(我们不考虑懒惰计算(lazy evaluation)时),这一解释是自然的。但是Scheme中,这里“展开和收缩”或“延迟计算”是递归带来的吗?不是。正如练习1.5所说明的,是采用正则序的if带来的。

如果将正则序作为讨论的默认条件(下面的迭代也使用if),尾递归技术使得“递归函数”按照迭代/循环的方式执行。因此,Scheme就不需要for、while等语法糖。

(define (factorial n)

(fact-iter 1 1 n))

(define (fact-iter product counter max-count)

(if (> counter max-count)

product

(fact-iter (* counter product)

(+ counter 1)

max-count)))

这里,函数fact-iter是一个递归函数,但是计算过程中由几个状态变量控制。We callthis an iterative process.In general, an iterative process is one whose state can be summarized by afixed number of
state variables, together with afixed rule that describes how the state variables should be updated as theprocess moves from state to state and an (optional) end test that specifiesconditions under which the
process should terminate.当然,用for将state variables、rule of update和an (optional) end test集中起来,这个语法糖,挺好。

练习1.9 – 1.10

树形递归

Fibonacci number:

(define (fib n)

(cond ((= n0) 0)

((= n1) 1)

(else(+ (fib (- n 1))

(fib (- n 2))))))

(练习1.9)尾递归的一个特点,被替代的函数,作为递归表达式的第一个符号。

这个代码解释了树形递归,但是从效率的角度,存在大量重复计算。如何设计尾递归代码?

其他,跳过。高阶函数见3.

太多数学题了。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-04 15:57:52

Scheme 4 Javaer-2.功能抽象的相关文章

与Scheme共舞

发表在<程序猿>2007年7月刊上.不log上写帖子不用考虑版面限制,所以这里的帖子比发表的啰嗦点.赵健平编辑,Jacky,和刘未鹏都给了我非常多帮助,在这里一并谢了.免费的Scheme实现非常多.我用的是PLT Scheme,能够到这里下载.PLT Scheme的IDE(Dr. Scheme)支持Emacs的键盘绑定,用emacs的老大们应该喜欢.Dr.Scheme内置中文支持: 以下是正文: 不能影响你思考方式的编程语言不值得学习 – Alan Perlis[1] 不少朋友问,为什么要学S

抽象模型

//编程不仅是一门技术,更是一门艺术 //实例化的工厂,实例出合适的对象,多态的应用 //----------对象的返回-- //同一类的属性,方法可以随便调用 //不能只满足于写完代码运行结果正确就完事,时常 //考虑如何让代码更加简炼,更加容易维护,容易扩展和复用,只有这样才可以是真的提高.写出优雅的代码真的是一种很爽的事情 //抽象模型 // 抽象模型之间的关系 // 界面逻辑 //-------------------------- // Operation oper; // oper

MIT Scheme 的基本使用

安装和启动 启动 在 Windows 下正确安装 MIT Scheme 系统后,程序菜单里将有一个 MIT Scheme 目录,其中包含: Documentation:以浏览器方式打开 HTML 形式的 Scheme 文档 MIT GNU Scheme:Edwin 环境下启动 Scheme.Edwin 是一个类似 emacs 的编辑器 如果喜欢用命令行交互方式,可以用下述命令建一个快捷命令,放在你的桌面或者命令菜单里.注意将目录修改为你的系统安装目录: "C:\Program Files\MIT

5.抽象工厂模式-abstractfactory

初识抽象工厂模式 定义 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 结构和说明 AbstractFactory:? 抽象工厂,定义创建一系列产品对象的操作接口. ConcreteFactory:? 具体的工厂,实现抽象工厂定义的方法,具体实现一系列产品对象的创建. AbstractProduct:? 定义一类产品对象的接口 ConcreteProduct:? 具体的产品实现对象,通常在具体工厂里面,会选择具体的产品实现对象,来创建符合抽象工厂定义的方法返回的产品类型的对

[以太坊源代码分析] V. 从钱包到客户端

以太坊作为一种数字货币以太币的运行系统,显然它也会有类似于钱包的客户端程序,用来提供管理账户余额等功能.我们知道,存放(或者绑定,挂靠)以太币的账户,在代码中以Address类型变量存在,所以能够管理多个以太坊账户应该属于客户端程序基本功能之一.本文会从管理账户信息的代码包开始,自底向上的介绍以太坊客户端程序的一些主要模块.1. 管理账户信息的代码包accounts 在以太坊源代码的accounts代码包中,呈现账户地址的最小结构体叫Account{},它的主要成员就是一个common.Addr

Django View(视图系统)

Django View 官方文档 一个视图函数(类),简称视图,是一个简单的 Python 函数(类),它接受Web请求并且返回Web响应.响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. 无论视图本身包含什么逻辑,都要返回响应.代码写在哪里也无所谓,只要它在你当前项目目录下面.为了将代码放在某处,大家约定成俗将视图放置在项目(project)或应用程序(app)目录中的名为 views.py 的文件中. 一.FBV和CBV 1.1 FBV FBV(f

Django基础三之视图函数

Django基础三之视图函数 本节目录 一 Django的视图函数view 二 CBV和FBV 三 使用Mixin 四 给视图加装饰器 五 Request对象 六 Response对象 一 Django的视图函数view 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. 无论视图本身包含什么逻辑,都要返回响应.代码写在哪里也无所谓,只要它在你当前项

view 视图函数

一 Django的视图函数view 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. 无论视图本身包含什么逻辑,都要返回响应.代码写在哪里也无所谓,只要它在你当前项目目录下面.除此之外没有更多的要求了——可以说“没有什么神奇的地方”.为了将代码放在某处,大家约定成俗将视图放置在项目(project)或应用程序(app)目录中的名为views.py的

03.Django基础三之视图函数

一 Django的视图函数view 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. 无论视图本身包含什么逻辑,都要返回响应.代码写在哪里也无所谓,只要它在你当前项目目录下面.除此之外没有更多的要求了--可以说"没有什么神奇的地方".为了将代码放在某处,大家约定成俗将视图放置在项目(project)或应用程序(app)目录中的名为view