Scheme 语言概要(下)
数据库schema含义
数据库 sc hema含义数据库Sche ma有两种含义,一种是概念上的Schem a,指的是一组DDL语句集,该语句集完整地描述了数据库的结构。
还有一种是物理上的 Sche ma,指的是数据库中的一个名字空间,它包含一组表、视图和存储过程等命名对象。
物理Schem a 可以通过标准SQL语句来创建、更新和修改。
例如以下SQL语句创建了两个物理Sc hema: crea te sc hemaSCHEM A_A;c reate tabl e SCH EMA_A.CUST OMERS(ID i nt no t nul l,……); cre ate s chema SCHE MA_B;creat e tab le SC HEMA_B.CUS TOMER S(IDint n ot nu ll,……);简单的说:就是一个数据库用户所拥有的数据库的对象。
比如sco tt用户建立了表,索引,视图,存储过程等对象,那么这些对象就构成了sc hema sco tt在一个数据库中可以有多个应用的数据表,这些不同应用的表可以放在不同的s chema之中,同时,每一个s chema对应一个用户,不同的应用可以以不同的用户连接数据库,这样,一个大数据库就可以根据应用把其表分开来管理。
不同的s chema之间它们没有直接的关系,不同的shcem a之间的表可以同名,也可以互相引用(但必须有权限),在没有操作别的sc hema的操作根权下,每个用户只能操作它自己的sc hema下的所有的表。
不同的s chema下的同名的表,可以存入不同的数据(即sc hema用户自己的数据).----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------如果我们想了解数据库中的User和Schem a到底什么关系,那么让我们首先来了解一下数据库中U ser和S chema到底是什么概念。
1-最美丽的编程语言Scheme——基本表达式
最美丽的编程语言Scheme——基本表达式Scheme被很多人誉为“世界上最美丽的编程语言”。
偶也被他们的话所打动,于是乎开始了Scheme之旅。
目前Scheme大多用于科研,商用的比较少。
但即便如此,也丝毫不会影像其“美丽”。
下面就请大家一起跟我走进Scheme的世界罢。
玩Scheme与其它编程语言一样,需要一个开发环境。
我们可以通过Google搜索到MIT-GNU-Scheme。
它有Windows版、Linux版以及Mac OS X版。
基于你们所用的操作系统下载相应的版本。
我用过Windows版和Mac OS X版,其实界面都一样——都是控制台。
我们进入程序后,可以通过按下Ctrl+h,然后再按t,来看向导。
这里教你如何使用这个工具。
我们先按下Ctrl+x,然后按下b,然后进入Scheme表达式计算模式。
下面就让我们看看Scheme的一个最简单的表达式:1 + 2我们在工具中输入:[cpp]view plaincopyprint?1. (+ 1 2)1. (+ 1 2 3 4 5)2. ; Value: 153. (+ 10 (- 100 20))4. ; Value: 905. (+ 1 (* 3 4) (- 2 4) (/ 6 3))6. ; Value: 131. (+ 1 1.5)2. ;Value: 2.53. (/ 3 2)4. ;Value: 3/25. (/ 3.0 2.0)6. ;Value: 1.5下面我们将介绍Scheme中如何定义一个变量。
在Scheme中定义一个变量,在概念上是将该变量与表达式关联起来。
比如我们定义一个x为2:[cpp]view plaincopyprint?1. (define x 2)2. ;Value: x1. (define x 2)2. ;Value: x3. (+ x 10)4. ;Value: 125. (define y (/ 3 2))6. ;Value: y7. (+ y 0.5 x)8. ;Value: 4.9. (+ y 0.1)10. ;Value: 1.6。
scheme语言介绍
Scheme 语言介绍Wolfgang Kreutzer翻译:寒蝉退士原文:/~wolfgang/cosc302/Cha p2.3.html译者声明:译者对译文不做任何担保,译者对译文不拥有任何权利并且不负担任何责任和义务。
APL 如同钻石,有着美妙的晶体结构;它的所有部分都以一致和优美的方式关联在一起。
但是如果你尝试以任何方式扩展这种结构- 即使是增加另一个钻石- 你将得到一个丑陋的杂种。
在另一方面,LISP 如同泥球。
你可以向它增加任意数量的泥巴,它看起来还是个泥球。
[J. Moses, as quoted by Steele and Sussman (1978)].译序:本文是介绍人工智能的一本书的一章,Lisp 的赫赫声名缘于它是人工智能专家们做符号处理的主要编程工具。
从计算机技术的角度来说,Lisp 是函数式编程语言的代表,有着“数学基础”领域中lambda 演算的理论背景。
Lisp 的修正版本Scheme 有着一定的研究价值。
目录:历史演化和关键概念用Scheme 编程概述表示和解释- 符号& 值数据类型和它们的操作导引控制流Lambda 表达式和环境执行的嵌套上下文过程- 定义、测试、调试递归额外特征对风格的一些建议总结和看法历史演化和关键概念在人工智能的很多研究中,Lisp 家族语言是最古老的、并仍然是最广泛使用的工具。
不象Fortran 那样,在很大程度上出于经济上的动机而保持语言存活了四分之一个世纪,Lisp 在AI 社区的兴旺是因为它的某些特征的优越。
Lisp 至关重要的一个方面是试探性程序开发的概念。
符号到值的任何提交(commitment)可以延迟直到这样的决定不可避免,即使如此它可以用很小的代价逆转(reverse)。
这允许我们快速的探索可供选择的设计并逐步增加的建造程序。
Lisp 的语法是简单的、并且它的程序自然的表示为数据结构,所以很容易写操纵其他程序的程序。
scheme用法
scheme用法Scheme是一种通用的编程语言,于1975年由Gerald Jay Sussman和Guy L. Steele Jr.设计。
Scheme的设计目标是提供一种简洁而强大的语言,使程序员能够方便地表达解决问题的思路。
它是一种函数式编程语言,具有强大的元编程能力和尾递归优化特性。
在Scheme中,函数是一等公民,意味着函数可以作为参数传递给其他函数,也可以作为返回值返回。
这种特性使得Scheme非常适用于编写高阶函数和递归算法。
Scheme支持匿名函数的定义,可以使用λ表达式来创建一个匿名函数。
Scheme提供了许多内置的基本表达式和操作符,例如加法、乘法、条件语句等。
Scheme还支持列表和元组的操作,可以通过cons操作将元素添加到列表头部,通过car和cdr操作来取得列表的第一个元素和剩下的部分。
列表在Scheme中起着重要的作用,并且可以用于实现更复杂的数据结构。
Scheme有着简洁而灵活的语法,采用括号表示程序的结构。
这种语法称为S表达式,使得Scheme代码具有统一的形式,容易理解和生成。
此外,Scheme也支持宏的使用,程序员可以通过宏来定义自己的语法扩展,以便更好地表达问题。
Scheme具有强大的元编程能力,即能够在程序运行过程中创建和改变程序的结构和行为。
这使得程序可以在运行时进行自我修改和自我优化,提高了编程的灵活性和效率。
总结而言,Scheme是一种简洁而强大的编程语言,具有函数式编程、元编程和拥有统一形式的S表达式等特性。
它提供了丰富的操作符和表达式,以及强大的列表操作,使得程序员能够设计出优雅而高效的程序。
无论是用于函数式编程还是学习编程思维,Scheme都是一个值得探索的语言。
第四讲Schemappt课件
xmlns
<!-- Schema 主体-->
</xs:schema>
属性
要使用任意一种 XML Schema 数据类型,需指定 XML Schema 数据类型的命名空间
XML Schema 中的元素
数据类型
语法:
<… type = "float"/>
允许作为数据类型的值
char boolean
int float number
基本类型数据类型
整型 小数 实数 时间 时间间隔
XML Schema 中的元素
Schema 中的元素或属性使用 <element> 和 <attribute> 标签来声明
<xs:schema xmlns:xs="/2001/XMLSchema"
> Schema 元素
支持其他功能,如开放内容模型和命名 空间集成
XML Schema 的优势
使用 XML 语法创建,所以可以使用相同的软 件工具处理 XML Schema 和 XML 实例
所需的数据管理和数据行政管理支出较少,使 得总体规划支出较低
由于 XML Schema 是在 Namespace Recommendation(命名空间建议)之后定稿 的,所有命名空间的概念可以为设计所使用并 涵盖。因此,使用 XML Schema 可以定义利用 命名空间声明的词汇集
Schema 支持的数据类型
XML Schema 数据类型
Schema 支持的数据类型
ID
IDREF
IDREFS
ENTITY
ENTITIES
NMTOKEN
NMTOKEN S
scheme
guile> (define name "tomson") guile> name "tomson" guile> (string-length name) ; 取字符串的长度 6 guile> (string-set! name 0 #\g) ; 更改字符串首字母(第 0 个字符)为小写 字母 g (#\g) guile> name "gomson" guile> (string-ref name 3) ; 取得字符串左侧第 3 个字符(从 0 开始) #\s
作为 Lisp 变体,Scheme 是一门非常简洁的计算语言,使用它的编程人员可以 摆脱语言本身的复杂性,把注意力集中到更重要的问题上,从而使语言真正成为 解决问题的工具。本文分为上、下两部分来介绍 scheme 语言。
一.Scheme 语言的特点
Scheme 语言是 LISP 语言的一个方言(或说成变种),它诞生于 1975 年的 MIT,对 于这个有近三十年历史的编程语言来说,它并没有象 C++,java,C#那样受到商 业领域的青睐,在国内更是显为人知。但它在国外的计算机教育领域内却是有着 广泛应用的,有很多人学的第一门计算机语言就是 Scheme 语言。
从上面的操作中可以看出来,只要 not 后面的参数不是逻辑型,其返回值均为#f。
数字型(number)
它又分为四种子类型:整型(integer),有理数型(rational),实型(real),复 数型(complex);它们又被统一称为数字类型(number)。
scheme中文教程
C. HANSON
K. M. PITMAN
M. WAND
谨以此纪念 Robert Hieb
1998 年 2 月 20 日
摘要
本报告给出程序设计语言 Scheme 的定义性描述。 Scheme 是 Lisp 程序设计语言的方言,由 Guy Lewis Steele Jr. 和 Gerald Jay Sussman 发明,具有静态作用域和严格尾递归 的特点。它的设计目标是拥有异常清晰、简明的语义和较 少的表达式异构方式。包括命令式、函数式和消息传递式 风格在内的绝大多数程序设计模型都可以用 Scheme 方便 地表述。
whitespace 6 with-input-from-file 32 with-output-to-file 32 write 33; 13 write-char 33
#x 19; 35
zero? 20
Index 47
算法语言 Scheme 修订5报告
王咏刚 试译 v 0.9.5
RICHARD KELSEY, WILLIAM CLINGER, AND JONATHAN REES (编者)
第 7 章用扩展 BNF 给出了 Scheme 语言的形式语法,并为 其定义了形式指称语义。形式语法和语义后面有一个使用 Scheme 语言的示例。
本报告的最后是参考文献列表和依字母顺序排列的索引。
目录
概述 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1 Scheme 概论 . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
#t 23 tail call 尾调用 7 tan 21 token 记号 34 top level environment 最高层环境 16; 6 transcript-off 34 transcript-on 34 true 7; 10, 23 truncate 21 type 类型 7
scheme如何记忆
Scheme如何记忆Scheme语言是一种基于Lisp的函数式编程语言,具有简洁、优雅的语法和强大的表达能力。
对于初学者来说,Scheme的记忆可能是一个挑战。
然而,通过一些技巧和方法,我们可以更容易地掌握Scheme语言的特点和用法。
了解Scheme的基本概念在学习Scheme语言之前,需要了解一些基本概念。
首先,Scheme是一种基于符号表达式的语言,它以括号表达式(S表达式)作为语法基础。
另外,Scheme是一种函数式编程语言,函数在Scheme中被视为一等公民,可以像其他数据一样进行操作。
掌握Scheme的数据结构Scheme中最基本的数据结构包括数字、字符串、布尔值和列表。
数字可以是整数或实数,字符串用双引号括起来,布尔值为#t和#f,表示真和假。
列表是Scheme中最常用的数据结构,使用括号括起来,元素之间用空格分隔。
熟悉Scheme的基本语法了解Scheme的基本语法是记忆Scheme的关键。
在Scheme中,括号是用于表示函数应用和代码块的重要符号。
每个括号表达式由一个操作符和零个或多个操作数组成,操作符的位置在最左边。
理解Scheme的函数定义和调用函数在Scheme中使用define关键字进行定义,使用lambda关键字表示匿名函数。
函数调用的语法是将函数名放在括号中,后面跟着参数列表。
调用函数时,Scheme采用应用序求值规则,即先求值参数,然后将其传递给函数。
探索Scheme的递归和高阶函数递归是函数式编程的重要特性,Scheme语言天生支持递归。
通过递归,我们可以实现对数据结构的高效处理。
此外,Scheme还支持高阶函数,即可以接受函数作为参数或返回函数的函数,这种特性使得Scheme可以实现更为灵活和抽象的编程。
深入了解Scheme的惰性求值Scheme是一种惰性求值语言,它仅在需要时才求值表达式。
这种特性可以提高程序的效率和简洁性,但也需要注意避免潜在的副作用。
了解Scheme的惰性求值规则有助于更好地理解和记忆Scheme的行为。
scheme语法
Scheme是一种函数式编程语言,其语法主要包括以下几个部分:
1. 表达式:Scheme的基本语法结构是由一系列的表达式组成,每个表达式都被一对括号包围。
一个基
本的表达式由一个操作符和零个或多个操作数组成。
例如,(+ 1 2)表示对1和2进行求和,"+"是操作符,"1"和"2"是操作数。
2. 数据类型:Scheme中有多种数据类型,包括整数、浮点数、布尔值、字符、字符串以及列表等。
例
如,'(1 2 3)表示一个包含三个整数元素的列表。
3. 函数:在Scheme中,函数是一等公民,可以作为其他函数的参数和返回值。
函数可以通过lambda表
达式定义,例如,(lambda (x y) (+ x y))表示一个接受两个参数x和y,返回它们的和的函数。
4. 变量:在Scheme中,变量用于存储值,可以使用赋值语句来给变量赋值。
例如,(define x 10)表示
将变量x的值设置为10。
5. 控制结构:Scheme的控制结构包括条件语句、循环语句等。
例如,(if <condition> <true-
expression> <false-expression>)表示当条件为真时执行true-expression,否则执行false-
expression。
6. 宏:Scheme允许使用宏定义自己的语法结构。
宏可以用来简化复杂的语法结构或者扩展语言的语
法。
以上是Scheme语法的一些基本组成部分,更多详细信息可以查阅Scheme的教程或者相关书籍。
数据库中的Schema是什么?
数据库中的Schema是什么?翻译自:在数据库中,schema(发音“skee-muh” 或者“skee-mah”,中文叫模式)是数据库的组织和结构,schemas and schemata都可以作为复数形式。
模式中包含了schema对象,可以是表(table)、列(column)、数据类型(data type)、视图(view)、存储过程(stored procedures)、关系(relationships)、主键(primary key)、外键(foreign key)等。
数据库模式可以用一个可视化的图来表示,它显示了数据库对象及其相互之间的关系以上是模式图的一个简单例子,显示了三个表及其数据类型、表之间的关系以及主键和外键,以下是数据库模式的一个更复杂的例子。
在这种情况下,模式图分为四个部分:(1)Customer Data(客户数据):与客户有关的数据,如姓名,地址等(2)Business(业务):业务所需的数据,例如员工,商店位置,付款细节等(3)Inventory(库存):所有产品的细节。
在这里,产品是电影,所以它包含电影标题,类别,演员等数据。
(4)Views(视图):关于用于评估的数据的特别观点,所以通过这些模式图,我们可以进一步创建一个数据库,实际上,MySQL Workbench允许我们直接从图中生成一个Create Table脚本,然后我们就可以直接用这个脚本去创建一个数据库,还可以直接将一个数据库转换为一个关系图表。
Schema和DataBase是否等同?涉及到数据库的模式有很多疑惑,问题经常出现在模式和数据库之间是否有区别,如果有,区别在哪里。
取决于数据库供应商对schema(模式)产生疑惑的一部分原因是数据库系统倾向于以自己的方式处理模式(1)MySQL的文档中指出,在物理上,模式与数据库是同义的,所以,模式和数据库是一回事。
(2)但是,Oracle的文档却指出,某些对象可以存储在数据库中,但不能存储在schema中。
(译)Scheme简明教程1-序及进入Scheme编程
(译)Scheme简明教程1-序及进⼊Scheme编程Scheme简明教程序⾔:这是⼀份Scheme编程语⾔的⼊门教程。
旨在作为⼀份快速上⼿指南,以便初学者在步⼊更⼴更深的正式课程前可以获取该语⾔上⼿所需的应⽤知识(⼊门后,请读者更深⼊的学习Scheme)。
本教程将引导读者写出简明实⽤的Scheme代码。
尽管不会覆盖到Scheme语⾔的⽅⽅⾯⾯,但我们也不会避开这门语⾔中的很有⽤处但让⼈觉得难理解、⽣涩、罕见、不标准、甚⾄奇怪的部分。
⽐如call-with-current-continuation、系统接⼝和多样化的⽅⾔等。
我们会基于解决问题来做⼀些讨论,但不会是单纯的探索⾼深的纯语⾔理论。
我因此删除了许多经典的Scheme指南。
所以本教程不会出现深层次的教学⽅法、不会详细的关注Scheme语义、没有元数据解释、没有对深层次的实现的讨论、也没有对Scheme语⾔优点的评价。
这并不是说这些内容不重要,但它们对想快速上⼿的初学者来说没有实际意义。
到底能够有多快?我不确定是否有⼈能够在三周时间内⾃学完Scheme,但我确实听说了Scheme的⼊门应该只需要半天的⼯夫。
Scheme标准⼿册,虽然很细⾄完备,但也只不过只有50页。
最终在某个下午,你会完全理解Scheme和它的标准,但在那之前没有⼈会知道需要度过多少个让⼈觉得满头雾⽔的下午。
希望读者能尽快领悟,这就是我的简明教程。
Acknowledgment: Matthias Felleisen , Matthew Flatt (鸣谢部分翻译省略)开发环境:译者⽤的是⼤学的STK环境,可在附属⽂件中查找。
第⼀章进⼊Scheme编程按惯例,我们总是以⼀个可以输出”Hello, World!”字符串的控制台程序开始。
打开你最习惯的⽂本编辑器,⽤以下内容创建⼀个名为hello.scm的⽂件:;The first program(begin(display"Hello, World!")(newline))第⼀⾏是注释语句,当Scheme遇到⼀个分号,它将忽略该分号以及这⼀⾏分号之后的语句。
Schema的基本语法
Schema的基本语法XSDL(XML Schema定义语言)由元素、属性、命名空间和XML文档种的其他节点构成的。
一、XSD中的元素XSD文档至少要包含:schema根元素和XML模式命名空间的定义、元素定义。
1、schema根元素语法如下:<xsd:schema xmlns:xsd=“/2001/XMLSchema”>…</xsd:schema>在XSD中必须定义一个且只能定义一个schema根元素。
根元素中包括模式的约束、XML 模式命名空间的定义,其他命名空间的定义、版本信息、语言信息和其他一些属性。
2、元素语法如下:<xsd:element name=”user” type=”xsd:string” />XSD中的元素是利用element标识符来声明的。
其中name属性是元素的名字,type属性是元素值的类型,在这里可以是XML Schema中内置的数据类型或其他类型。
例子:<xsd:schema xmlns:xsd=“/2001/XMLSchema”><x sd:element name=”user” type=”xsd:string” /></xsd:schema>以上文档对应的有效XML文档如下:<?xml version=”1.0”?><user>string</user>在元素的定义中还有2个属性:minOccurs和maxOccurs。
其中minOccurs定义了该元素在父元素中出现的最少次数(默认为1,值为大于等于0的整数),maxOccurs定义了该元素在父元素中出现的最多次数(默认为1,值为大于等于0的整数)。
在maxOccurs中可以把值设置为unbounded,表示对元素出现的最多次数没有限制。
例子:<xsd:schema xmlns:xsd=/2001/XMLSchema><xsd:element name=”user” type=”xsd:string” minOccurs=”0” maxOccurs=”unbounded” /></xsd:schema>表示为元素user的类型为string,出现的次数最少为0(也就是可选),最多不限制。
scheme语言
scheme语言
Scheme是一种函数式编程语言,它遵循Lisp编程风格,并由Gerald Jay Sussman和Guy L. Steele Jr.在1975年开发。
Scheme是一种简洁而优雅的编程语言,它具有一些特殊的特性,如动态类型、动态作用域、递归和尾递归等。
Scheme具有强大的函数和过程的支持,它允许将函数作为参数传递和返回,这种特性被称为高阶函数。
此外,Scheme还有一种强大的宏系统,允许用户定义自己的语法扩展。
与其他编程语言相比,Scheme语言的语法非常简单,它使用括号表示函数调用,并使用前缀表示法。
例如,下面是一个使用Scheme定义的函数,计算一个数的平方:
```scheme
(define (square x)
(* x x))
```
Scheme提供了许多基本的数学函数和过程,例如加法、乘法、除法等。
此外,它还提供了列表处理和递归的简便方法。
Scheme是一种高度灵活和可扩展的语言,它具有清晰的语法和简单的语义。
它被广泛应用于教学和研究领域,也被用作脚本语言和开发工具。
第4讲Schema基本语法
目标命名空间
如何理解属性elementFormDefault、attributeFormDefault? 用来指示 XML Schema 处理程序把这个 XML schema 中定义的元素或者类型放到哪个命名空 间。一般情况下设置为qualified。 。 当elementFormDefault=“qualified” 时,所有子元素、全局元素或者数据类型将被限定放到目 标命名空间; 而当elementFormDefault=“unqualified” 时,所有子元素将不被限定在任何名空间。全局元素 或者数据类型将被放到目标命名空间。
Schema中的注释
一般方式:<!-- --> 专门方式:用元素来添加注释 <annotation…/> 优点:可读性强,其他应用程序也能读取 <annotation…/>元素结构 <document…/> <appinfo…/> <annotation…/>元素位置 各种Schema组件定义的开始部分,用于说明该组件的作用。 通常每份Schema文档所包含的第一个元素是<annotation…/>元素。
引入多个有命名空间的XMLSchema实例
<?xml version="1.0" encoding="GB2312"?> <书籍列表 xmlns:xsi="/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="book2Namespace.xsd" xmlns:crazy="/crazy" xmlns:crazyitnet="" xsi:schemaLocation="/crazy crazy.xsd crazyitnet.xsd"> <计算机书籍>疯狂Java讲义</计算机书籍> <crazy:简要介绍>疯狂Java联盟特色:所有技术发帖,必有回复!</crazy:简要介绍> <crazyitnet:地址>广州</crazyitnet:地址> </书籍列表> 总结: (1)一份XML文档中可以引入无数份有命名空间的XMLSchema。 (2)一份XML文档中最多只能引入一份无命名空间的XMLSchema。 (3)有命名空间的XMLSchema具有更好的可扩展性,建议定义XMLSchema时为其根元 素 指定targetNamespace属性,该属性的属性值就是该XMLSchema所对应的命名空间。
schema规则
schema规则[schema规则],以中括号内的内容为主题,写一篇1500-2000字文章,一步一步回答首先,让我们来了解一下什么是[schema规则]。
Schema规则是一种定义数据结构的标记语言,用于定义数据实体之间的关系和属性。
它用于描述数据的结构、数据类型、约束条件和关系等细节。
这种规则可以被应用于各种领域,例如数据库设计、API设计、网络通信等。
在本文中,我们将深入探讨[schema规则]的相关细节,包括它的基本概念、语法、常见的应用场景以及如何使用它来构建数据结构。
让我们一起来了解吧!1. 什么是[schema规则][schema规则]是一种用于定义数据结构的标记语言。
它定义了数据实体之间的关系和属性,以及它们之间的约束和限制。
通过使用[schema规则],我们可以确保数据在应用程序中的一致性和完整性。
具体来说,它包括以下几个方面:- 数据结构:[schema规则]定义了数据实体的结构,包括属性名称、属性类型和属性之间的关系。
- 数据类型:[schema规则]规定了每个属性的数据类型,例如整数、字符串、日期等。
- 约束条件:[schema规则]可以定义属性的限制条件,例如必填、唯一性和范围等。
- 关系:[schema规则]可以定义实体之间的关系,例如一对一、一对多和多对多等。
通过使用[schema规则],我们可以确保数据的一致性和有效性,并在应用程序中建立一个具有良好可维护性的数据结构。
2. [schema规则]的语法[schema规则]的语法通常有一定的标准和约定,下面是一个简单的示例:{"type": "object","properties": {"name": {"type": "string"},"age": {"type": "integer"},"email": {"type": "string","format": "email"}},"required": ["name", "email"]}在上面的示例中,我们定义了一个对象类型的[schema规则],包含了三个属性:name、age和email。
Scheme 语言概要
简介:Scheme语言是LISP语言的一个方言(或说成变种),它诞生于1975年的MIT,对于这个有近三十年历史的编程语言来说,它并没有象C++,java,C#那样受到商业领域的青睐,在国内更是显为人知。
但它在国外的计算机教育领域内却是有着广泛应用的,有很多人学的第一门计算机语言就是Scheme语言。
作为Lisp 变体,Scheme 是一门非常简洁的计算语言,使用它的编程人员可以摆脱语言本身的复杂性,把注意力集中到更重要的问题上,从而使语言真正成为解决问题的工具。
本文分为上、下两部分来介绍scheme 语言。
一.Scheme语言的特点Scheme语言是LISP语言的一个方言(或说成变种),它诞生于1975年的MIT,对于这个有近三十年历史的编程语言来说,它并没有象C++,java,C#那样受到商业领域的青睐,在国内更是显为人知。
但它在国外的计算机教育领域内却是有着广泛应用的,有很多人学的第一门计算机语言就是Scheme语言。
它是一个小巧而又强大的语言,作为一个多用途的编程语言,它可以作为脚本语言使用,也可以作为应用软件的扩展语言来使用,它具有元语言特性,还有很多独到的特色,以致于它被称为编程语言中的"皇后"。
下面是洪峰对Scheme语言的编程特色的归纳:词法定界(Lexical Scoping)∙动态类型(Dynamic Typing)∙良好的可扩展性∙尾递归(Tail Recursive)∙函数可以作为值返回∙支持一流的计算连续∙传值调用(passing-by-value)∙算术运算相对独立本文的目的是让有编程基础(那怕是一点点)的朋友能尽快的掌握Scheme语言的语法规则,如果您在读完本文后,发现自己已经会用Scheme语言了,那么我的目的就达到了。
回页首二.Scheme语言的标准与实现R5RS (Revised(5) Report on the Algorithmic Language Scheme)Scheme语言的语法规则的第5次修正稿,1998年制定,即Scheme 语言的现行标准,目前大多数Scheme语言的实现都将达到或遵循此标准,并且几乎都加入了一些属于自己的扩展特色。
Scheme语言概要
Scheme语言概要(上)Scheme语言是LI SP语言的一个方言(或说成变种),它诞生于1975年的M IT,对于这个有近三十年历史的编程语言来说,它并没有象C++,java,C#那样受到商业领域的青睐,在国内更是显为人知。
但它在国外的计算机教育领域内却是有着广泛应用的,有很多人学的第一门计算机语言就是Schem e语言。
3评论宋国伟 (gwsong***********)吉林省德惠市信息中心2003 年12 月01 日∙内容form嵌套Scheme语言中允许form的嵌套,这使它可以轻松的实现复杂的表达式,同时也是一种非常有自己特色的表达式。
下图示意了嵌套的稍复杂一点的表达式的运算过程:变量定义可以用def ine来定义一个变量,形式如下:(define变量名值)如: (define x 123) ,定义一个变量x,其值为123。
更改变量的值可以用set!来改变变量的值,格式如下:(set! 变量名值)如: (set! x "hello") ,将变量x的值改为"hello"。
Scheme语言是一种高级语言,和很多高级语言(如pytho n,perl)一样,它的变量类型不是固定的,可以随时改变。
回页首四.数据类型1. 简单数据类型逻辑型(boolea n)下图表示了由pairs定义形成的列表:Scheme语言概要(下)Scheme语言是LI SP语言的一个方言(或说成变种),它诞生于1975年的M IT,对于这个有近三十年历史的编程语言来说,它并没有象C++,java,C#那样受到商业领域的青睐,在国内更是显为人知。
但它在国外的计算机教育领域内却是有着广泛应用的,有很多人学的第一门计算机语言就是Schem e语言。
android scheme原理
android scheme原理
Android中的Scheme是一种URL协议,用于在应用程序之间进行数据传输和通信。
原理如下:
1. Android应用程序通过定义一个Intent过滤器来注册自己所支持的Scheme。
这样其他应用程序就可以使用这个Scheme
来访问该应用程序。
2. 当一个应用程序需要使用Scheme来启动其他应用程序时,它会创建一个Intent对象并设置其action为
Intent.ACTION_VIEW,data为包含Scheme的URL。
3. 系统会根据Intent中的数据匹配已注册的Intent过滤器。
如果有多个匹配项,则系统将弹出一个对话框,让用户选择要启动的应用程序。
4. 如果只有一个匹配项,系统会启动该应用程序,并将包含Scheme的URL传递给它。
5. 接收应用程序可以通过调用getIntent().getData()来获取传递过来的URL。
6. 应用程序可以根据接收到的URL执行相应的操作,例如打开指定的界面,显示特定的内容,或者进行数据交换等。
通过使用Scheme,Android应用程序可以实现跨应用程序的数据传输和通信,提供更加丰富和交互性的用户体验。
scheme.tao
预计的章节结构是这样的, 依大家的需要再作改动:* 开始之前* 数据结构的本质论* 无处不在的函数解释 Scheme 中无处不在的函数的概念* 无名的能量之源Lambda 运算的基本介绍* 无始无终的太极Scheme 运行原理, apply/eval 机制* 唯心主义的对象管理系统Scheme 的对象管理机制和 GC 原理* 创造机器的机器用 Scheme 制造 Scheme 程序, 或用 Scheme 写 Scheme 解释器的一些内容 一个应用* 真实存在的时光机器神奇的 call/cc 机制, 可能会引入讲一点 amb 的内容这一段比较深, 没有很大的把握能写好* 终章的名实之辩在其他语言/系统中类 Scheme 的设计, 由此的启发等* 开始之前这是一篇 Scheme 的介绍文章. Scheme 是一个 LISP 的方言, 相对于 CommonLISP 或其他方言, 它更强调理论的完整和优美, 而不那么强调实用价值. 我在 学习 Scheme 的时候, 常想的不是 "这有什么用", 而是 "为什么" 和 "它 的本质是什么". 我觉得这样的思考对学习计算机是非常有益的.我不知道 "Scheme 之道" 这个题目是否合适, 我还没到能讲 "XXX 之道" 的时候.但 Scheme 确实是一个极具哲学趣味的语言, 它往往专注于找出事物的 本质, 用最简单, 最通用的方法解决问题. 这样的思路下, 我们会碰到许多以往 不会遇到,或不甚留意的问题, 使我们对这些问题, 以及计算机科学的其他方面 有新的认识和思考.讲 Scheme 的好书有很多, 但 Scheme 在这些书中往往就像指着月亮的慧能的手指或是 道家的拂尘, 指引你发现计算机科学中的某些奇妙之处, 但 Scheme 本身却不是重点. 如SICP (Structure and Interpretation of Computer Programs) 用Scheme 来指引学生学习计算机科学中的基本概念; HTDP (How to designprograms) 用Scheme 来介绍程序设计中常用的技巧和方法. 而这篇文章, 着眼点也不是scheme 本身, 或者着眼点不在 scheme 的 "形", 而在与 scheme 的 "神".怎么写一个好的 scheme 程序不是我的重点, 我的重点是 "这个设计真 美妙", "原来本质就是如此", 如是而已. Scheme 的一些理论和设计启发了我 , 使我在一些问题, 一些项目上有了更好的想法. 感念至今, 所以写一系列小文 将我的体会与大家分享.要体验 Scheme, 当然首先要一个 Scheme 的编程环境. 我推荐 drScheme(), 跨平台, 包括了一个很好的编辑和调试界面 . Debian/Ubuntu 用户直接 apt-get 安装即可.希望读者有基本的编程和数据结构知识. 因为解释 Scheme 的很多概念时, 这些知识是必须的.* 数据结构的本质论** 世界的终极问题这两个可能是人类对世界认识的终极问题: 世界上最基本的, 不可再分的物质单位是什么? 这些最基本的物质单位是怎么组成这个大千世界的?Scheme 也在试图解答这个问题.Scheme 认为以下两种东西是原子性的, 不可再分的: 数, 符号. 数这个好理解,符号这个概念就有点麻烦了. 做个比方, "1" 是一个数字, 但它其实是一个符 号, 我们用这个符号去代表 "1" 这个概念, 我们也可以用 "一" 或 "one" 代表这个概 念, 当然 "1" 也可以表示 "真" 的概念, 或者什么都 不表示. 而 kyhpudding 也 是一个 Scheme 中的符号, 它可以代表任何东西, Scheme 能理解的或不能理解的. 这都没所谓, Scheme 把它作为一个原子单位对 它进行处理: 1 能跟其他数字作运 算得出一个新的数字, 但 1 始终还是 1, 它 不会被分解或变成其他什么东西, 作 为符号的 kyhpudding 也大抵如此.下一个问题是: 怎么将原子组成各种复合的数据结构 --- 有没有一种统一的方 法?我们从最简单的问题开始: 怎么将两个对象聚合在一起? 于是我们引入了 "对 " (pair) 的概念, 用以聚合两个对象: a 和 b 组成的对, 记为:(a . b)画图(a . b) - b|a请大家将头往左侧 45 度, 这其实就是一个二叉树.如果是要聚合三个或以上的数据呢? pair 的方法还适用吗? 我们是否需要引入 其他方法? 答案是不需要, 我们递归地使用 pair 结构就可以了. 聚合 a, b, c, 记 为 (a . (b . c)), 它的简化记法是 (a b . c).大家都能想到了, 递归地使用 pair 二叉树的结构, 就能表达任意多个对象组成的序列. 比如 (a b . c), 画图就是:(a b . c) - (b . c) - c| |a b请大家继续将头左侧 45 度. 这样的一个表示序列的树的特点是, 树的左结点是成员对象, 右结点指向一颗包含其他成员的子树. 但大家也发现了一个破例: 图中的 c 是右边的叶子. 解决这个问题的办法是: 我们引入一个 "无" 的概念:(a b c . nil) - (b c . nil) - (c . nil) - nil| | |a b c这个无的概念我们用 "()" 来表达 (总不能什么都没有吧). 记 (a . ()) 为 (a). 那么上图就可以表示为 (a b c). 这样的结构我们就叫做列表 --- List. 这是 Scheme/LISP 中应用最广的概念. LISP 其实就是 "LISt Processing" 的意思.这样的结构表达能力很强, 因为它是可递归的, 它可以表达任何东西. 比方说, 一 个普通的二叉树可以像这样表示 (根 (根 左子树 右子树) 右子树). 大家也 可以 想想其他的数据结构怎么用这种递归的列表来表示.** 开始编程啦好了, 我们可以开始写一点很简单的 Scheme 程序. 比方说, 打入 1, 它就会返回 1. 然后, 打入一个列表 (1 2), 出错鸟... 打入一个符号: kyhpudding, 也出错鸟......于是我们就要开始讲一点点 Scheme 的运作原理了. 刚才我们讲了 Scheme 中的数据结构, 其实不但是 Scheme 处理的数据, 整个 Scheme 程序都是由这样的列表和原子对象构成的, 一个合法的 Scheme 数据结构就是一个 Scheme 语句. 那么这样的语句是怎么运行的呢? 总结起来就是三条逻辑:1. 如果那是一个数, 则返回这个数2. 如果那是一个符号, 则返回该符号所绑定的对象. (这个概念我们会迟点解释)3. 如果那是一个列表, 把列表的第一项作为方法, 其他作为参数, 执行之.所以, 我们可以试试这个 (+ 1 2), 这下就能正确执行了.那么, 如果我就想要他返回 (+ 1 2) 这个列表呢? 试试这样 (quote (+ 1 2))quote 是一个很特殊的操作, 意思是它的参数不按规则处理, 而是直接作为数据返回. 我们会常常用到它, 所以也有一个简化的写法 '(+ 1 2), 在前面加一个 单引号就可以了. 这样子, 'kyhpudding 也能有正确的输出了.那么我们可以介绍三个原子操作, 用以操纵列表. 其实, 所谓操纵列表, 也只是操纵二叉树而已. 所以我们有这么三个操作:* cons: 将它的两个参数组合起来, 形成新的二叉树/pair* car: 返回参数的左子树* cdr: 返回参数的右子树通过以下几个操作, 结合对应的二叉树图, 能比较好的理解这个 Scheme 最基础的设计:(cons 'a (cons 'b '()))(car '(a b c))(cdr '(a b c))* 无处不在的函数** 基本的函数概念Scheme 是一门函数式语言, 因为它的函数与数据有完全平等的地位, 它可以在运行 时被实时创建和修改. 也因为它的全部运行都可以用函数的方式来解释, 莫能例外.比方说, 把 if 语句作为函数来解释? (if cond if-part else-part) 是这么一个特殊的函数: 它根据 cond 是否为真, 决定执行并返回 if-part 还是 else-part. 比 如, 我可以这样写:((if (i-am-feeling-lucky) + -) my-happyness 1)if 函数会根据我开心与否 (i-am-feeling-lucky 是一个由我决定它的返回值的函数 :P) 返回 + 或 - 来作为对我的开心值的操作. 所谓无处不在的函数, 其意义大抵 如此.把一串操作序列当成函数呢? Scheme 是没有 "return" 的, 把一串操作序列当作一 个整体, 它的返回值就是这一串序列的最后一个的返回值. 比如我们可以写(begin (+ 1 2) (+ 3 4))它的返回是 7.** 无名的能量之源接下来, 我们就要接触到 Scheme 的灵魂 --- Lambda. 大家可以注意到 drScheme 的图标, 那就是希腊字母 Lambda. 可以说明 Lambda 运算在 Scheme 中是多么重要.NOTE: 这里本来应该插一点 Lambda 运算的知识的, 但是一来我自己数学就不怎么好没什么信心能讲好, 二来讲太深了也没有必要. 大家如果对 Lambda 运算的理论有 兴趣的话, 可以自行 Google 相关资料.Lambda 能够返回一个匿名的函数. 在这里需要注意两点: 第一, 我用的是 "返回" 而不是 "定义". 因为 Lambda 同样可以看成一个函数 --- 一个能够生成函数的函数 . 第二, 它是匿名的, 意思是, 一个函数并不一定需要与一个名字绑定在一起, 我们 有时侯需要这么干,但也有很多时候不需要.我们可以看一个 Lambda 函数的基本例子:((lambda (x y) (+ x y)) 1 2)这里描述了一个加法函数的生成和使用. (lambda (x y) (+ x y)) 中, lambda 的第一个参数说明了参数列表, 之后的描述了函数的行为. 这就生成了一个函数 , 我们 再将 1 和 2 作用在这个函数上, 自然能得到结果 3.我们先引入一个 define 的操作, define 的作用是将一个符号与一个对象绑定起来 . 比如(define name 'kyhpudding)之后再敲入 name, 这时候 Scheme 解释器就知道如何处理它了, 它会返回一个 kyhpudding.我们自然也可以用 define 把一个符号和函数绑定在一起, 就得到了我们常用的有名函数.(define add(lambda (x y) (+ x y)))做一个简单的替换, 上面的例子就可以写成 (add 1 2), 这样就好理解多了.上面的写法有点晦涩, 而我们经常用到的是有名函数, 所以我们有一个简单的写法, 我们把这一类简化的写法叫 "语法糖衣". 在前面我们也遇到一例, 将 (quote x)写成 'x 的例子. 上面的定义, 我们可以这样写(define (add x y) (+ x y))Lambda 运算有极其强大的能力, 上面只不过是用它来做传统的 "定义函数" 的工作 . 它的能力远不止如此. 这里只是举几个小小的例子:我们经常会需要一些用于迭代的函数, 比如这个:(define (inc x) (+ x 1))我们也需要减的, 乘的, 还有其他各种乱七八糟的操作, 我们需要每次迭代不是 1, 而是 2, 等等等等. 我们很自然地有这个想法: 我们写个函数来生成这类迭代函数如何? 在 Scheme 中, 利用 lambda 运算, 这是可行且非常简单的. 因为在 Scheme 中,函数跟普通对象是有同样地位的, 而 "定义" 函数的 lambda, 其实是能够动态地为 我们创造并返回函数对象的. 所以我们可以这么写:(define (make-iterator method step)(lambda (x) (method x step)))没有语法糖衣的写法是:(define make-iterator(lambda (method step)(lambda (x) (method x step))))这个简单的例子, 已经能够完成我们在 C 之类的语言无法完成的事情. 要生成上面 的 inc 函数, 我们可以这么写:(define inc (make-iterator + 1))这个例子展示的是 Scheme 利用 Lambda 运算得到的能力. 利用它, 我们可以写出制造函数的函数, 或者说制造机器的机器, 这极大地扩展了这门语言的能力 . 我们在 以后会有更复杂的例子.接下来, 我们会介绍 Scheme 的一些语言特性是怎么用 Lambda 运算实现的 --- 说 Scheme 的整个机制是由 Lambda 驱动的也不为过.比如, 在 Scheme 中我们可以在任何地方定义 "局部变量", 我们可以这么写:(let ((x 1) (y 2)) 运用这些局部变量的语句)其实 let 也只不过是语法糖衣而已, 因为上面的写法等价于:((lambda (x y)运用这些局部变量的语句)1 2)** 一些常用的函数虽然说这篇文章不太注重语言的实用性. 但这里还是列出我们经常用到的一些操作, 这能极大地方便我们的编程, 大家也可以想想他们是怎么实现的.- cond相当于 C 中的 switch(cond(条件1 执行体)(条件2 执行体)(else 执行体))- 循环语句没有循环语句...... 至少没有必要的循环语句. Scheme 认为, 任何的循环迭代都 可以用递归来实现. 我们也不用担心递归会把栈占满, 因为 Scheme 会自动处理尾递 归的情况. 一个简单的 0 到 10 迭代可以写成这样.(define (iterate x)(if (= x 10)x(iterate (+ x 1))))(iterate 0)很明显, 当我们递归调用 iterate 的时候, 我们不必保存当前的函数环境. 因为我 们递归调用完毕后就马上返回, 而不会再使用当前的环境, 这是一给尾递归的例子. Scheme 能自动处理类似的情况甚至做一些优化, 不会浪费多余的空间, 也不会降低 效率. 所以完全可以代替循环.当然我们有些便于循环迭代的操作, 大家可以试试自己实现他们. (当然在解释器内 部通常不会用纯 scheme 语句实现他们). 我们最常用的是 map 操作(map (lambda (x) (+ x 1)) '(1 2 3))运行一下这个例子, 就能理解 map 的作用了.- 更多的数据操作* cadr cddr caddr 之类, 就是 car 和 cdr 的组合, 大家可以一个个试 .drScheme 支持到 cadddr...* append: 将两个列表拼接在一起.预告:这一节我们介绍了最重要的 lambda 的概念, 不知道这样是否足够清楚呢?下面一节, 我们的任务是分析 ``Scheme 是怎么运作的'' 这个问题其实相当于 ``一个函数是怎么被执行的''. 我们将会遇到一个 apply/eval 的无限循环~ 请继续关注~我想其他语言的入门教程都不会有这么一节: 这门语言的运作原理是怎么样的 . 但 这么一节内容是 Scheme 的入门教程必有的. Scheme 把它最核心, 最底层的机制都 提供出来给用户使用, 使它有非常强大的能力. 所以知道它的运行机理是非常重要的.这一节和下一节都是在分析 Scheme 的运行原理. 在这一节中, 我们会用一个太极图来分析一条 Scheme 语句是怎么被执行的. 在下一节, 我们会在这一节的基础上引 入 Scheme 的对象/内存管理机制. 从而得到一个比较完整的 Scheme 运行原理, 并用 Scheme 语言表示出来.我们先从 eval 和 apply 的用法说起. eval 接受一个参数, 结果是执行那个参数的语句, 而 apply 则接受两个参数, 第一个参数表示一个函数, 第二个参数是作用于 这个函数的参数列表. 例如:(eval '(+ 1 2))(apply + '(1 2))我们可以轻易发现, 这两者是可以轻易转化的:(define (eval exp) (apply (car exp) (cdr exp)))(define (apply method arguments) (eval (cons method arguments)))但是显然, 真正的实现不可能如此, 不然 eval 一次就没完没了地转圈了. 我们在前面提到 Scheme 的基本运行逻辑, 其实也是 eval 的基本原理:1. 如果那是一个数, 则返回这个数2. 如果那是一个符号, 则返回该符号所绑定的对象.3. 如果那是一个列表, 把列表的第一项作为方法, 其他作为参数, 执行之.我们来实现一个这样的逻辑, 要注意的是, 下面的 eval 和 apply 的写法都只是说 明概念, 并不是真实可运行的. 但用 Scheme 写一个 Scheme 解释器是确实可行的:(define (eval exp)(cond((symbol? exp) 返回 exp 所指的对象)((list? exp) (apply (eval (car exp)) (cdr exp)))(else 'error)))在第三项, 我们很自然地用了 apply 来实现. 注意 apply 接受的第一个参数必须是一个函数对象, 而不能是一个类似 add 的名字, 所以我们要递归地调用 eval 解析 出它的第一个参数. 那么 apply 要怎么实现呢? 我们来看一个实例:有定义: (define (add x y) (+ x y))执行: (add x (+ y 1))用 eval 执行它的时候, 会执行(apply (lambda (x y) (+ x y)) '(x (+ y 1))).在执行它的时候 , 为了运行它, 我们要知道 add 和 x 代表什么, 我们还得知道 ( + y 1) 的结果, 否则我们的计算无法继续下去. 我们用什么来求得这些值呢--- 显然是eval. 因此 apply 的处理流程大致如下:(define (apply method arguments)(执行 method (map eval arguments)))我们得到的还是一个互相递归的关系. 不过这个递归是有尽头的, 当我们遇到原子对象时, 在 eval 处就会直接返回, 而不会再进入这个递归. 所以 eval 和 apply 互 相作用, 最终把程序解释成原子对象并得到结果. 这种循环不息的互相作用, 可以表 示为这样一个太极:这就是一个 Scheme 解释器的核心.然而, 我们上面的模型是不尽准确的. 比如, (if cond if-part else-part) 把这个放入 apply 中的话, if-part 和 else-part 都会被执行一遍, 这显然不是我们希 望的. 因此, 我们需要有一些例外的逻辑来处理这些事情, 这个例外逻辑通常会放在 eval. (当然理论上放在 apply里也可以, 大家可以试一下写, 不过这样在 eval 中也要有特殊的逻辑之处 "if"这个符号所对应的值). 我们可以把 eval 改成这样(define (eval exp)(cond((symbol? exp) 返回 exp 所指的对象)((list? exp)(cond((if? (car exp)) (if 的特殊处理 (cdr exp)))(还有其他的例如 quote, cond 的都得放在这里)(else (apply (eval (car exp)) (cdr exp)))))(else 'error)))这样我们的逻辑就比较完整了.另外 apply 也要做一些改动, 对于 apply 的 method, 它有可能是类似 "+" 这样的内置的 method, 我们叫它做 primitive-proceure, 还有由 lambda 定义的 method , 他们的处理方法是不一样的.(define (apply method arguments)(if (primitive-procedure? method)(处理内置函数 (map eval arguments))(处理 lambda (map eval arguments))在下一节, 我们就会从 lambda 函数是怎么执行的讲起, 并再次修改 eval 和 apply 的定义, 使其更加完整. 在这里我们会提到一点点 lambda 函数的执行原理, 这其实算是一个 trick 吧.我们这样定义 lambda 函数(lambda (参数表) 执行体)那么我们在 apply 这个 lambda 函数的时候会发生什么呢? apply 会根据参数表和 参数做一次匹配, 比如, 参数表是 (x y) 参数是 (1 2), 那么 x 就是 1, y 就是 2 . 那么, 我们的参数表写法其实可以非常灵活的, 可以试试这两个语句的结果:((lambda x x) 1 2) <= 注意两个 x 都是没有括号的哦((lambda (x . y) (list x y)) 1 2 3)这样 "匹配" 的意义是否会更加清楚呢? 由于这样的机制, 再加上可以灵活运用eval 和 apply, 可以使 Scheme 的函数调用非常灵活, 也更加强大.下节预告: 下一节, 我们又会一下引入很多概念. 我们在前面的章节很简单地讲了 define 和 let 的作用, 那它到底是怎么实现的呢? 对一个名字, 我们如何在运行中正确得到它所对应的对象? Scheme 的自动垃圾收集机制是怎么工作的? 如何判定一个对象已经成为垃圾? 值得一提的是, Java 等语言也采用了同样的垃圾收集方法. 我们就在下一节来解释这些有趣的问题.* 唯心主义的对象管理系统** 关于对象既然这一节我们要讲对象管理系统. 我们首先就要研究对象, 研究在 Scheme 内部是如何表示一个对象. 在 Scheme 中, 我们的对象可以分成两类: 原子对象和 pair.我们要用一种办法唯一地表示一个对象. 对原子对象, 这没什么好说的, 1 就是 1,2 就是 2. 但是对 pair, 情况就比较复杂了.(define a '(1 . 2))(define b '(1 . 2))如果我们修改了 a 的 car 的值, 我们不希望 b 的值也同样的被改变. 因此虽然 a 和 b 在 define 时的值一样, 但他们不是相同的对象, 我们要分别表示他们. 但是 在这个时候(define a '(1 . 2))(define b a)a 和b 应该指的是同一个对象, 不然 define 的定义就会很尴尬 (define 不是赋值, 而是绑定). 修改了 a 的 car, b 也应该同时改变.答案很明显了: 对 pair 对象, 我们应把它表示为一个引用 --- 熟悉 Java 的同学 也会知道一个相同的原则: 在 Java 中, 变量可以是一个原子值 (如数字), 或者是 对一个复合对象的引用.在这里我们引入一组操作, 它可以帮助测试, 理解这样的对象系统:* set!: 不要漏了叹号, 修改一个符号的绑定* set-car!: 修改 pair 中左边值的绑定* set-cdr!: 修改 pair 中右边值的绑定* eq?: 测试两个对象是否相等* equal?: 测试两个对象的值是否相等.我们可以进行如下测试:(define a '(1 . 2))(define b '(1 . 2))(set-car! a 3)查看 a 和 b 的值(define a '(1 . 2))(set-car! a 3)查看 a 和 b 的值(eq? '(1 2) '(1 2))(equal? '(1 2) '(1 2))另外我们可以想想以下操作形成的对象的结构:(define a '(1 2))(define b (cons 3 (cdr a)))它形成的结构应该是这样的a: (1 2) - (2) - ()|b: (3 2) ---+所以 (eq? (cdr a) (cdr b)) 的值应该是真.** lambda 的秘密接下来我们要研究: Scheme 是怎么执行一个 lambda 函数的? 运行一个 lambda 函 数, 最重要的就是建立一个局部的命名空间, 以支持局部变量 --- 对 Scheme 来说, 所谓局部变量就是函数的参数了. 只要建立好这样的一个命名空间, 剩下的事情就 是在此只上逐条运行语句而已了.我们首先可以看这样的一个例子:(define x 10)((lambda (x) x) 20)结果当然是 20, 这说明了 Scheme 在运行 lambda 函数时会建立一个局部的命名空 间 --- 在 Scheme 中, 它叫做 environment, 为了与其他的资料保持一致, 我们会 沿用这个说法, 并把它简写为 env. 而且这个局部 env 有更高的优先权 .那我们似乎可以把寻找一个符号对应的对象的过程描述如下, 这也是 C 语言程序的 行为:1. 先在函数的局部命名空间里搜索2. 如果找不到, 在全局变量中搜索.但是 Scheme 中, 函数是可以嵌套的:(define (test x)(define (test2 x) x)(test2 (+ x x)))(test 20)很好, 这不就是一个栈的结构吗? 我们在运行中维护一个 env 的栈, 搜索一个名称绑定时从栈顶搜索到栈底就可以了.这在 Pascal 等静态语言中是可行的 (Pascal 也支持嵌套的函数定义). 但是在 Scheme 中不行 --- Scheme 的函数是可以动态生成的, 这会产生一些栈无法处理的情 况, 比如我们上面使用过的例子:(define (make-iterator method step)(lambda (x) (method x step)))(define inc (make-iterator + 1))(define dec (make-iterator - 1))执行 inc 和 dec 的时候, 它执行的是 (method x step), x 的值当然很好确定 ,但是method 和 step 的值就有点麻烦了. 我们调用 make-iterator 生成 inc 和dec 的时候, 用的是不同的参数, 执行 inc 和 dec 的时候, method 和 step 的值当然应该不一样, 应该分别等于调用make-iterator 时的参数. 这样的特性 , 就没法用一个栈的模型来解释了.一个更令人头痛的问题是: 运行 lambda 函数时会创造一个 env, 现在看起来, 这个 env 不是一个临时性的存在, 即使是在函数执行完以后, 它都有存在的必要 , 不然像上例中, inc 在运行时就没法正确地找到 + 和 1 了. 这是一种我们从未遇到的模型.我们要修改函数的定义. 在 Scheme 中, 函数不仅是一段代码, 它还要和一个 environment 相连. 比如, 在调用 (make-iterator + 1) 的时候, 生成的函数要与执行 函数 make-iterator 实时产生的 env 相连, 在这里, method = +, step = 1; 而调用 (make-iterator - 1) 的时候,生成的函数是在与另一个 env --- 第二次调用 make-iterator 产生的 env 相连,在这里, method = -, step = 1. 另外, 各个 env 也是相连的. 在执行函数 inc 时, 他会产生一个含有名称 x 的 env, 这个 env 要与跟lambda 函数相连的的 lambda相连. 这样我们在只含有 x 的env 中找不到method, 可以到与其相连的 env 中找. 我们可以画图如下来执行 (inc 10) 时的 env 关系:inc: ((x 10)) -> ((method +) (step 1)) -> ((make-iterator 函数体))这里的最后一项就是我们的全局命名空间, 函数 make-iterator 是与这个空间相连 的.于是我们可以这样表示一个 env 和一个 lambda 函数对象: 一个 env 是这么一个二元组 (名称绑定列表 与之相连的上一个 env). 一个 lambda 是一个这样的三元组: (参数表 代码 env).由此我们需要修改 eval 和 apply. 解释器运行时, 需要一直保持着一个 "当前 env". 这个当前 env 应该作为参数放进 eval 和 apply 中, 并不断互相传递. 在生成 一个 lambda 对象时, 我们要这样利用 env:(define (make-lambda 参数表 代码 env)(list 参数表 代码 env))这样就可以表示 lambda 函数与一个 env 的绑定. 那么我们执行 lambda 函数的行为可以这么描述:(define (make-env func)(list (match-binding (car func) (caddr func))))match-binding 就是我们上面介绍过的参数表匹配过程.(define (run-lambda func)(let ((new-env (make-env func)))(eval (cadr func) new-env)))这样我们就可以完全清楚的解释 make-iterator 的行为了. 在执行 (make-iterator + 1) 时, make-env 生成了这样的一个 new-env:(((method +) (step 1)) global-env)global-env 是 (((make-iterator 函数体)) '())这个 new-env 会作为参数 env 去调用 eval. 在 eval 执行到 lambda 一句时, 又会以这样的参数来调用 make-lambda, 因此这样的一个 env 就会绑定到这个 lambda 函数上. 同理, 我们调用 (make-iterator - 1) 的时候, 就能得到另一个 env 的绑定.这种特性使 "函数" 在 scheme 中的含义非常丰富, 使用非常灵活, 以下这个例子实现了非常方便调试的函数计数器:(define (make-counter method)(let ((counter 0))(lambda arguments(if (eq? (car arguments) 'print)counter(begin。
SCHEME语言
4GSCHEME 语言是怎么来的导言Scheme 是LISP的一个方言(dialect)。
著名的SICP 书就是以Scheme 为教学语言(实际上SICP 的作者就是Scheme 的作者)。
虽然Scheme 本身只是一个精简化的适合教学的语言,可它首先提出的一些重要的思想,引领了新一代的LISP语言的出现。
实际上,LISP语言发展的历史是连续的,之所以我在这里人为的把LISP 的发展史划分为上一代和现代,是因为随着Scheme 首次引入并规范化了一些重要概念,LISP 语言出现了很多以前从来没有大规模普及的新特性。
以Common LISP为代表的LISP语言也因为这些新特性,而焕发了第二春。
人所共知的Paul Graham 大叔,借着这一波LISP复兴的浪潮,不光写出了On Lisp 这样的好书;而且还用Common LISP写出了一个在线电子商务平台,在1998 年的时候以近 5 千万美元的价格卖给了Y ahoo! (凭借这笔买卖, Paul 大叔现在经营着Y Combinator 天使投资,成为硅谷著名的天使)。
前段时间卖给Google 的ITA,负担着世界上大部分的航班资讯查询,核心系统也是Common LISP。
虽然不该把Common LISP的很多成就全部归结到Scheme, 但Scheme 作为一个重要的历史分水岭,探究一下它的历史来源还是很有趣的。
函数作为一级对象我们都知道LISP是一个函数式的编程语言。
在LISP中,函数是一种基本类型。
类比的看,C 家族的语言中,整数是一个基本的类型,所以,整数类型的变量既可以作为参数传递给一个函数,也可以作为返回值返回。
比如,两个整数求和这个函数,用 C 家族的语法就是int add(int a, int b);因为在LISP里面,函数也成了基本类型。
如果我们有一个add 函数如下:(define (add x y) (+ x y))显然,它在LISP里就和 C 里的int 一样,能够作为参数传递给其他函数。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Scheme 语言概要(下)
谈完了scheme 的基本概念、数据类型和过程,我们接着介绍scheme 的结构、递归调用、变量和过程的绑定、输入输出等功能。
一.常用结构
如执行(fun 123) 则返回值为"not a string",这样的功能在C++或JAVA中实现的话可能会很费力气。
cond结构
Scheme语言中的cond结构类似于C语言中的switch结构,cond的格式为:
Scheme语言中只有if结构是系统原始提供的,其它的cond,case,and,or,另外还有do,when,unless 等都是可以用宏定义的方式来定义的,这一点充分体现了Scheme的元语言特性,关于do,when等结构的使用可以参考R5RS。
二.递归调用
用递归实现阶乘
我们可以将下面的调用(factoral 4),即4的阶乘的运算过程图示如下:
这只是一种简单的循环定义,过程有两个参数,第一个参数是循环的初始值,第二个参数是循环终止值,每次增加1。
相信读者朋友一定会写出更漂亮更实用的循环操作来的。
三.变量和过程的绑定
除了apply,map以外,Scheme语言中还有很多,诸如:eval,delay,for-each,force,
call-with-current-continuation等过程绑定的操作定义,它们都无一例外的提供了相当灵活的数据处理能力,也就是另初学者望而生畏的算法,当你仔细的体会了运算过程中用到的简直妙不可言的算法后,你就会发现Scheme语言设计者的思想是多么伟大。
四.输入输出
在输入输出操作方面,还有很多相关操作,读者可以参考R5RS的文档。
五.语法扩展
这是一个比较简单的宏定义,但对理解宏定义来说是比较重要的,理解了他你才会进一步应用宏定义。
在规则((start exp1) exp1) 中,(start exp1) 是一个参数时的模板,exp1是如何处理,也就是原样搬出,不做处理。
这样(start form1) 和(form1) 的功能就相同了。
在规则((start exp1 exp2 ...) (let ((temp exp1)) (start exp2 ...))) 中,(start exp1 exp2 …) 是多个参数时的模板,首先用let来绑定局部变量temp为exp1,然后用递归实现处理多个参数,注意这里说的是宏定义中的递归,并不是过程调用中的递归。
另外在宏定义中可以用省略号(三个点)来代表多个参数。
在Scheme的规范当中,将表达式分为原始表达式和有源表达式,Scheme语言的标准定义中只有原始的if分支结构,其它均为有源型,即是用后来的宏定义成的,由此可见宏定义的重要性。
附上面的定义在GUILE 中实现的代码。
六. 其它功能
define 特殊的form
(define x 9) ,define不是一个过程,它是一个不用求所有参数值的特殊的form,它的操作步骤是,初始化空间,绑定符号x到此空间,然后初始此变量。
必须记住的东西
下面的这些定义、过程和宏等是必须记住的:
define,lambda,let,lets,letrec,quote,set!,if,case,cond,begin,and,or等等,当然还有其它宏,必需学习,还有一些未介绍,可参考有关资料。
走进Scheme语言的世界,你就发现算法和数据结构的妙用随处可见,可以充分的检验你对算法和数据结构的理解。
Scheme语言虽然是古老的函数型语言的继续,但是它的里面有很多是在其它语言中学不到的东西,我想这也是为什么用它作为计算机语言教学的首选的原因吧。