软核硬壳
屡伤屡愈,屡愈屡伤
歪酷博客
« 上一篇: 信耶稣不合科学 下一篇: 匈牙利命名法zz »
My @ 2004-06-19 02:39

原文:http://www.cosc.canterbury.ac.nz/~wolfgang/cosc302/Chap2.3.html

译者声明:译者对译文不做任何担保,译者对译文不拥有任何权利并且不负担任何责任和
义务。

APL 如同钻石,有着美妙的晶体结构;它的所有部分都以一致和优美的方式关联在一起。
但是如果你尝试以任何方式扩展这种结构 - 即使是增加另一个钻石 - 你将得到一个丑陋
的杂种。在另一方面,LISP 如同泥球。你可以向它增加任意数量的泥巴,它看起来还是个
泥球。
[J. Moses, as quoted by Steele and Sussman (1978)].

译序:本文是介绍人工智能的一本书的一章,Lisp 的赫赫声名缘于它是人工智能专家们做
符号处理的主要编程工具。从计算机技术的角度来说,Lisp 是函数式编程语言的代表,有
着“数学基础”领域中 lambda 演算的理论背景。Lisp 的修正版本 Scheme 有着一定的研
究价值。


------------------------------------------------------------------------------
--

目录:
历史演化和关键概念

用 Scheme 编程

概述

表示和解释 - 符号 & 值

数据类型和它们的操作

导引控制流

Lambda 表达式和环境

执行的嵌套上下文

过程 - 定义、测试、调试


额外特征
本节总结对 Scheme 的简要介绍。尽管多数 Scheme 的主要特征已经被覆盖了,没有空间
做更多的风格讨论了。我们故意把我们的处置限制在据信是 Scheme 的本质的和可移植的
那些方面。Rees 和 Clinger (1986)给出这门语言的完整定义。有些额外的标准特征,特
别是在数值和输入/输出操作领域中。概念,比如引擎[Dybvig (1987),Hayes 和 Friedm
an (1984)],宏和语法扩展[Dybvig (1987)]没有提及;主要是因为仍然缺乏这些概念的标
准实现,尽管很多方言已经提供了一些这种设施。请注意本书不意图充当参考手册的替代
品。因此我们强烈建议使用你工作用的方言的参考手册,接着继续你的探索。

编程是需要实践的一种技巧,特别是对于“良好”风格的开发。读其他人写的程序是特别
重要的,然而写你自己的程序和从你的错误中学习是生死攸关的。

Scheme 好象特别适合于这种业务,因为它带给用户的不只是编码解决某些问题,还有寻找
特别优雅的公式表达。Friedman 评论一个良好的计算机语言为:“应当提供一个环境,程
序可以在其中为手头的问题创造性生成计算模型或范例。程序员构造范例的能力不应当受
到限制。我把易于构造范例称为语言的“易范例性”(paradigmicity)。有低易范例性的语
言是讨厌的。...我们如何建立有高易范例性的语言呢? 我们介入一些基本概念,组合这些
概念的一些方式,并且这么做的过程中我们利用了解决问题的多年经验。在现存的语言中
没有那个比 Scheme 更易范例性了。它的基本概念是过程、续体、引擎、条件和赋值语句
。所有东西都会合在复合和递归下,它预备了语法和语义扩展二者。... 使用这些基本概
念的实验和实践的越多,新范例出现的越快。” [Friedman in: Dybvig (1987), prefac


对风格的一些建议
Scheme 是一个高度交互式的语言,它带有鼓励试探性风格的问题解决的特征。这种属性使
学习过程变得容易。新的想法可以立即实验,它担当使困难的概念非神秘化的任务要比任
何“静态”的描述形式要好。表结构用来表示数据和程序二者。因为它们还强调了有层次
的嵌套和递归,这鼓励了“块状”的应用程序和创造分层设计。

有一些基本规则用来写有良好结构的 Scheme 程序,多数这些规则类似于在典型的 Lisp
教科书中给出的指导方针。Abelson 等人(1985) 的书和在本书中讨论的工具箱程序可以充
当有代表性的例子。

过程定义应当简要,并且它们应当面向一个单一的、定义良好的目的。任务应当尽可能的
分解到一些子任务中,如果它们延伸超过了一页,把它们委派给其他过程。过程还应当围
绕概念来组织,概念依次反映在正确的数据结构中。这个要求演化自分层设计的方法论,
强烈建议使用它。创建、查询、选择、显示和更改过程的概念给出对通常需要那种过程的
指导。

程序应当是可读的和易于理解的。这个原理对标识符命名和程序构造方式有明显暗示。标
识符应当是描述性的,并且它们应当提供与所表示的概念有关的助记符。还希望你遵从分
类标识符的特定格式惯例。例如,我们使用大写字母来开始工具箱过程的名字,而小写字
母用作系统定义的过程的名字。Scheme 使用特殊的后缀: "?" 用于谓词(就是返回 #t 或
#f 的函数)和 "!" 用于有“副作用”的所有过程(就是说,改变对非局部变量的绑定)。
因为 Scheme 是一个动态类型的语言,参数的命名应当反映它们的值。使用 aNumber 或
anAList 替代 n 或 l。尽管你可能开始时憎恨键入长名字、并可能感觉你的程序过于冗长
了,额外的努力以后会得到报答的。

在你的程序中使用清晰的结构将要求某些决断力,而你将最终发展出一种你自己的风格。
完成这个目标的唯一方法是阅读和评判其他人的代码,并采纳你喜欢的到你写的程序中。
因为这种决定通常涉及感性,除了维持一致性之外,不能给出一般的规则。不要惧怕实验
。如果你觉得增进了的理解能使你做出更好的工作,抛弃老的程序并再次开始。

递归和表结构在编程符号应用中同迭代和数组在数值应用中一样常见。尽管你需要做有意
识的努力来克服所有 Pascal 或 Fortran 条件反射,你应该使用它们发挥它们的全部优势
。递归是定义和处理重复和有规律结构的“自然的”和优雅的方式,并且这种结构很易于
表示为表。

set! 过程可能产生“非局部”的副作用,所以它有害于一个程序的可理解性。这导致一些
人完全反对它的使用并鼓吹没有任何副作用的“纯”函数式编程。在处理过程要按照复杂
的状态变化来描述的情况下,这种风格经常是非常不实际的,所以作者不赞同这种推理。
改变值绑定的能力是非常有用的工具,它的作用不能总是很方便的用任何其他方式完成。
你应当尽可能的细心的保持这种绑定的作用域为局部,并适当的加以文档。在很多情况下
,let 表达式、嵌套过程调用和递归能导致更清晰的结构。

深度嵌套的 cars 和 cdrs 经常是难于理解的,因此应当避免。处理这种深度递归结构的
更加可取的方法是使用多层解释,这样 car 和 cdr 的长链就变得不需要了。例如,(Get
XCoordinate (GetFirstPoint (GetBottomEdge (aTriangle)))) 比 (caar (caddr aTria
ngle)))更可取。使用适当的选择子(selector)函数也会使你的程序更加灵活并更易于维护
。对象封装的实质性利益也应当探究,因为使用这种象征(metaphor)有助于使你的程序更
加健壮和安全。

象很多其他强力特征一样,续体可能是危险的工具。尽管它们在某种程度上比“go to”语
句相关的想法更加“安全”,它们的正确使用在相当大程度上要求程序员方面的自我约束
。对“why”、“what”、“where”和“how”加以适当的文档也是基本的,更甚于更简单
的结构。因此续体应当保守的使用,用来实现其他方式不能实现的目标。即使你不应当以
它们的“原始”形式使用它们,但是应当把它们看作组合适当的高层结构的建造块(比如,
非局部 escape, 协同例程 ...)。

Scheme 的交互式本质允许你在过程写完之后立即测试它们。你应当完全利用这种可能性并
运行一组选择的测试个例,有效的和无效的二者都要有。

在编程风格上的多数一般指导方针也适用于 Scheme 程序。Kernighan & Plauger (1974)
和 Ledgard (1974) 给出了一个良好的总结。

程序应当适当的缩进和注释,尽管使用适当的标识符和有可能迅速的测试过程减少了注释
的数量但它们仍是需要的。过程的定义通常应当开始于一个对它功能的简要解释,如果从
它的名字看来不是很明显的。在复杂的应用中还应当有对类型、结构和这个标识符用途的
描述。除了这些考虑之外,应当使用注释来突出一段代码重要的部分。它们应当经常是解
释性的(就是说,在做“什么”)而不是纯描述性(就是说,是“如何”完成的)。缩进应当
是一致的并应当强调程序的结构。因为嵌套的过程的清单有着一种不幸的倾向,它会溢出
页面的右侧,在任何 scheme 缩进之下,都经常需要行使某些调整,在一致性和美观性之
间作出权衡。

所有信息都应当尽可能的模块化和局部化。全局变量应当非常保守的使用! Scheme 支持局
部变量和局部过程,你应当使用这些设施来把信息装载到正确的模块中。例如,任何只在
另一个过程内部调用的过程都应当嵌套到那个过程中。作为它的逻辑上的结论,这导致了
面向对象结构,尽管有些事例中过程是简单的,在其中使用与面向对象有关的额外的“脚
手架”是不正当的。

因为 Scheme 用作讨论很多重要的编程象征的一个工具,本书后面的章节将提供给出近一
步提示和察看这些建议应用的充分机会。

总结和看法
Lisp 是围绕符号操纵的想法建造的。原子和表是它的基本结构建造块。每个对象要么是一
个表要么是一个原子。表可以递归的定义,所以可以有表的表的表 ...,形成任意复杂的
树结构,表和原子可以被求值为要么数据要么是所谓的 lambda 表达式。事实上,Lisp 解
释器将求值它遇到的所有东西,除非被显式的引用了。

Lisp 是一个应用式和基于表达式的语言,这意味着解释的主体单元是圆括号表达式。“纯
” Lisp 禁止“副作用”。这个限制经常被证明是过分限制、并且实际语言在很大程度上
屏弃了它。所以 Lisp 通常不能被当作函数式语言。需要介入赋值的正确决断必须处理好
模块化的问题,这超出了本文的范围。Abelson 等人(1985) 的书的第三章是详细分析的好
来源。Lisp 表达式可以引用其他表达式,要么直接的要么通过把某种函数应用到参数。每
个对象,包括函数,可以动态的构造和操纵;所以我们可以有返回函数的函数,改变函数
定义的函数,等等。存储管理是自动进行的。对对象没有类型限制,但程序员可以通过选
择适当的标适符来细心的介入(数据)结构。尽管为变量声明关联上数据类型通常被认可为
编译型编程语言的重要特征,它在解释性环境没有多大用处。它的主要用处在于使编译器
可以优化存储和执行,并对程序做一致性检查。解释器动态的建立数据结构,所有优化并
不重要。自动的一致性检查可能使需要的,但是因为程序员在程序失败的时候有权访问所
有绑定的来源和值,错误预防通常不象编译环境中那么关键。它可以被高级的错误检查和
更正特征所取代。当然,效验和优化一个已经稳定了的程序仍使非常需要的。

递归和条件表达式合起来是 Lisp 的主要控制结构。这是恰当的,因为它允许容易的和优
雅的定义重复的规则的结构。在常规计算机体系上递归的低效一直是对 Lisp 的主要批评
之一。尽管这种讨论直到几年前还是有益的,现在在很大程度已经被新的实现技术和专用
“Lisp 机器”的出现所克服,Lisp 机器在微程序级别支持表和递归,但是,仍然可以公
平的说使用 Lisp 经常会导致“内存饥荒”的程序。

Lisp 是一个交互语言,支持试探风格的程序开发。结构编辑器和复杂的调试工具通常作为
它所嵌入的编程环境的一部分。这使编写 Lisp 函数的任务非常容易,而不用管众所周知
的那些错综复杂的圆括号。结构编辑器可以帮助圆括号恐惧症患者战胜 Lisp 稀少的语法
带来的多数缺点。

很多其他经常引证的缺点(比如,动态作用域,缺乏“块结构”,单一的数据类型,低效的
数值操作和计算效率)已经在新方言中以各种方式去除了。

尽管很多年过去了,仍然只有不多的讲授用 Lisp 编程的教科书,这种情况最近已经戏剧
性的改变了。现在已经有了针对不同方言的、对不同背景的读者广泛的教科书。Siklossy
(1976) 的书使最老的一本。它很大程度上限制自身到 Lisp 1.5 已经介入的那些特征。A
llan(1978) 仍是一本出色的技术性介绍,使用“M-表示法”使它很大程度上独立于任何特
定方言,它还包含了对实现要点的一个可靠的讨论。但是 Allen 的教科书对没有先前的编
程经验的学生可能是不可企及的,Touretzki(1984) 和 Hasemer(1984) 写的书明确的针对
这种“初学者”。Wilensky (1984) 是更加面向技术的另一个有趣的教科书。这本书有两
个版本可获得;一本基于 FranzLisp 而另一本基于 Common Lisp。Winston 和 Horn(198
4) 强调 AI 应用。他们的书是 Winston(1984) 的伙伴并且被重写了来确保 Common Lisp
兼容。Tanimoto(1987) 是关于 AI 方法论的一个新近的教科书。同很多这种教科书一样
它包含一个优秀的、但必须是简要的对 Lisp 的介绍。最后, Charniak 等(1980)写一本
教科书,基于 UCI Lisp,对于 AI 编程技术给予高级的对待,它的一个新版不久就会出版
。Abelson、Sussman 和 Sussman(1985) 仍是关于 Scheme 的最重要的教科书。Friedman 和
Felleisen(1986) 和 Eisenberg(1987) 提供一个要求更少的介
绍。Dybvig(1987),ChezScheme 的开发者,写带有一些更充实的例子的一本教科书,在其
中他还覆盖了如引擎和语义扩展这样的特征。有一个活跃的 Scheme 用户组通过在 MIT(uucp: Scheme@mc.lcs.mit.edu)的邮件列表交流。


相关文章:


评论 / 个人网页 / 扔小纸条
*昵称

已经注册过? 请登录

Email
网址
*评论
 


 
Calendar
网志文件夹
· 所有网志
· comp
· phy
· mood
· other
· flash memory
搜 索
友 情 链 接
· 歪酷博客
· 管理我的Blog
· Yuan Mei's Home Outside
· muscle's linux
· 王垠的主页
· 棒棒儿的MATLAB世界
· 玉棒
· arescor
· Conch
· Yuan Mei's Home Outside again
· ymei @ www.dns0755.net

订阅 RSS

0040455

歪酷博客