这是一本面向初学者的温和且循序渐进的Scheme教程。目标读者是仅有些许编程经验的PC用户。
如果你不满意于其它的教程,那么请尝试本书。我们有很多方法去解释像Scheme程序设计语言这样的抽象主题,这之中最好的方法取决于读者的能力以及素养。(没有对任何人来说都绝对完美的方法。)这也正是尽管已经有很多Scheme语言的教程,我还另写一本的原因所在。
本教程的目的在于给读者在Scheme程序设计上提供足够的知识和能力以便能够阅读最好的计算机科学教科书之一的——《计算机程序的构造和解释》(Structure and Interpreter of Computer Program,SICP)。SICP使用Scheme作为授课语言。
如果你不满意于其它的教程,那么请尝试本书。我们有很多方法去解释像Scheme程序设计语言这样的抽象主题,这之中最好的方法取决于读者的能力以及素养。(没有对任何人来说都绝对完美的方法。)这也正是尽管已经有很多Scheme语言的教程,我还另写一本的原因所在。
本教程的目的在于给读者在Scheme程序设计上提供足够的知识和能力以便能够阅读最好的计算机科学教科书之一的——《计算机程序的构造和解释》(Structure and Interpreter of Computer Program,SICP)。SICP使用Scheme作为授课语言。
2021年11月24日
2021年11月24日
2021年11月24日
2021年11月24日 作为Lisp语言大家族的一员,Scheme同样擅长于处理表。你应该理解表以及有关表的操作以掌握Scheme。表在在后面章节中的递归函数和高阶函数中扮演重要角色。
在本章中,我会讲解基本的表操作,例如cons,car,cdr,list和quote。
在本章中,我会讲解基本的表操作,例如cons,car,cdr,list和quote。
2021年11月24日 在前面的章节中,我已经讲解了:
如何安装MIT-Scheme;
Scheme解释器是如何对S-表达式求值;
基本的表操作;
在本章中,我会讲解如何自定义函数。由于Sheme是函数式编程语言,你需要通过编写小型函数来构造程序。因此,明白如何构造并组合这些函数对掌握Scheme尤为关键。在前端定义函数非常不便,因此我们通常需要在文本编辑器中编辑好代码,并在解释器中加载它们。
如何安装MIT-Scheme;
Scheme解释器是如何对S-表达式求值;
基本的表操作;
在本章中,我会讲解如何自定义函数。由于Sheme是函数式编程语言,你需要通过编写小型函数来构造程序。因此,明白如何构造并组合这些函数对掌握Scheme尤为关键。在前端定义函数非常不便,因此我们通常需要在文本编辑器中编辑好代码,并在解释器中加载它们。
2021年11月24日 上一章中,我讲解了如何定义函数。本章中,我会讲解如何通过条件编写过程。这个是编写使用程序很重要的一步。
2021年11月24日 在前面的章节中,我已经讲述了如何定义函数。在本节中,我讲介绍局部变量,这将会使定义函数变得更加容易。
2021年11月24日 本章中我会介绍重复。通过重复,你可以编写“通常的”程序。虽然也可以使用do表达式,但Scheme中通常通过递归实现重复。
2021年11月24日 高阶函数(Higher Order Function)是一种以函数为参数的函数。它们都被用于映射(mapping)、过滤(filtering)、归档(folding)和排序(sorting)表。高阶函数提高了程序的模块性。编写对各种情况都适用的高阶函数与为单一情况编写递归函数相比,可以使程序更具可读性。比如说,使用一个高阶函数来实现排序可以使得我们使用不同的条件来排序,这就将排序条件和排序过程清楚地划分开来。函数sort具有两个参数,其一是一个待排序的表,其二是定序(Ordering)函数。
2021年11月24日 通过前面章节的学习,你已经可以在Scheme的交互式前端中编写并执行程序了。在本章中,我讲介绍如何输入和输出。使用这个特性,你可以从文件中读取数据或向文件中写入数据。
2021年11月24日 因为Scheme是函数式语言,通常来说,你可以编写不使用赋值的语句。然而,如果使用赋值的话,有些算法就可以轻易实现了。尤其是内部状态和继续(continuations )需要赋值。
尽管赋值非常习见并且易于理解,但它有一些本质上的缺陷。参见《计算机程序的构造和解释》的第三章第一节“赋值和局部状态”以及《为什么函数式编程如此重要》。
R5RS中规定的用于赋值的特殊形式是set!、set-car!、set-cdr!、string-set!、vector-set!等。除此之外,有些实现也依赖于赋值。由于赋值改变了参数的值,因此它具有破坏性(destructive)。Scheme中,具有破坏性的方法都以!结尾,以警示程序员。
尽管赋值非常习见并且易于理解,但它有一些本质上的缺陷。参见《计算机程序的构造和解释》的第三章第一节“赋值和局部状态”以及《为什么函数式编程如此重要》。
R5RS中规定的用于赋值的特殊形式是set!、set-car!、set-cdr!、string-set!、vector-set!等。除此之外,有些实现也依赖于赋值。由于赋值改变了参数的值,因此它具有破坏性(destructive)。Scheme中,具有破坏性的方法都以!结尾,以警示程序员。
2021年11月24日 我只介绍了表和数,因为它们在Scheme中最为常用。然而,Scheme也有像字符(Character)、字符串(String)、符号(Symbol)、向量(Vector)等的其它数据类型,我将在11到14章节中介绍它们。
2021年11月24日 我会在本章讲解在Lisp/Scheme程序设计语言中极具特色的数据类型——符号。符号是一种通过地址管理字符串的数据。符号可以被如eq?这样运行迅速地函数处理,而纯字符串需要被更慢的equal?处理。由于符号可以被快速比较,它们被用于做关联表和哈希表的键,这些我将在下一章讲到。
2021年11月24日 本章中,我会讲解用于表示数据关联的关联表和哈希表。关联的数据是由键和值组成的序对,值由键唯一确定的。表1显示了书和作者构成的配对。书籍可以确定作者,反之由作者确定书籍则不可,这是因为一个作者可能会写很多本书。表1中,由于P. Graham和L.Carroll分别写了两本书,因此他们的书无法被作者的名字唯一确定。
2021年11月24日 本章中,我将讲解向量和结构体。
向量是一组通过整数索引的数据。与C语言中的数组不同,一个向量可以储存不同类型的数据。与表相比,向量更加紧凑且存取时间更短。但从另外一方面来说,向量是通过副作用来操作的,这样会造成负担。
Scheme中的结构体与C语言中的结构体类似。但Scheme中的结构体比C语言中的更容易使用,因为Scheme为结构体自动创建了读取函数和写入函数,这受益于Lisp/Scheme中的宏。
向量是一组通过整数索引的数据。与C语言中的数组不同,一个向量可以储存不同类型的数据。与表相比,向量更加紧凑且存取时间更短。但从另外一方面来说,向量是通过副作用来操作的,这样会造成负担。
Scheme中的结构体与C语言中的结构体类似。但Scheme中的结构体比C语言中的更容易使用,因为Scheme为结构体自动创建了读取函数和写入函数,这受益于Lisp/Scheme中的宏。
2021年11月24日 本章中,我会讲解如何自定义语法。用户定义语法称作宏(Macro)。Lisp/Scheme中的宏比C语言中的宏更加强大。宏可以使你的程序优美而紧凑。
宏是代码的变换。代码在被求值或编译前进行变换,程序会继续执行就像变换后的代码一开始就写好了一样。
你可以在Scheme中通过用符合R5RS规范的syntax-rules轻易地定义简单宏,相比之下,在Common Lisp中自定义语法就复杂多了。使用syntax-rules可以直接定义宏而不用担心变量捕获(Variable Capture)。另一方面,Scheme中定义那些无法用syntax-rules定义的复杂的宏就比Common Lisp要困难。
宏是代码的变换。代码在被求值或编译前进行变换,程序会继续执行就像变换后的代码一开始就写好了一样。
你可以在Scheme中通过用符合R5RS规范的syntax-rules轻易地定义简单宏,相比之下,在Common Lisp中自定义语法就复杂多了。使用syntax-rules可以直接定义宏而不用担心变量捕获(Variable Capture)。另一方面,Scheme中定义那些无法用syntax-rules定义的复杂的宏就比Common Lisp要困难。
2021年11月24日 本章介绍的是Scheme中特有的数据类型——继续(Continuation)。由于其他程序设计语言并没有这种数据类型,因此它难于理解。当下,你并不需要彻底理解清楚,只需要大致了解。
我会讲解广义的继续和简短地介绍Continuation-Passing-Style(CPS),然后再讲解Scheme中的继续。我认为通过这种方式理解继续会比较容易。
我会讲解广义的继续和简短地介绍Continuation-Passing-Style(CPS),然后再讲解Scheme中的继续。我认为通过这种方式理解继续会比较容易。
2021年11月24日 惰性求值(Lazy evaluation)是在需要时才进行求值的计算方式。惰性求值自然地在数据结构中包含递归,可以以简单的方式表示无限的概念,这种方式有利于程序的模块化。
2021年11月24日 非确定性是一种通过仅定义问题来解决问题的算法。非确定性程序自动选择符合条件的选项。这项技术很适合逻辑编程。